summaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1995-11-14 08:00:00 +0000
committer <ralf@linux-mips.org>1995-11-14 08:00:00 +0000
commite7c2a72e2680827d6a733931273a93461c0d8d1b (patch)
treec9abeda78ef7504062bb2e816bcf3e3c9d680112 /arch/mips
parentec6044459060a8c9ce7f64405c465d141898548c (diff)
Import of Linux/MIPS 1.3.0
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/.gdbinit7
-rw-r--r--arch/mips/Makefile140
-rw-r--r--arch/mips/TODO10
-rw-r--r--arch/mips/bios32.c8
-rw-r--r--arch/mips/boot/Makefile47
-rw-r--r--arch/mips/boot/a.out.c254
-rw-r--r--arch/mips/boot/compressed/Makefile45
-rw-r--r--arch/mips/boot/compressed/cache.S162
-rw-r--r--arch/mips/boot/compressed/crypt.h12
-rw-r--r--arch/mips/boot/compressed/gzip.h284
-rw-r--r--arch/mips/boot/compressed/head.S52
-rw-r--r--arch/mips/boot/compressed/inflate.c810
-rw-r--r--arch/mips/boot/compressed/lzw.h42
-rw-r--r--arch/mips/boot/compressed/misc.c438
-rw-r--r--arch/mips/boot/compressed/piggyback.c81
-rw-r--r--arch/mips/boot/compressed/unzip.c180
-rw-r--r--arch/mips/boot/compressed/xtract.c86
-rw-r--r--arch/mips/boot/head.S387
-rw-r--r--arch/mips/boot/loader.h24
-rw-r--r--arch/mips/boot/milo.c316
-rw-r--r--arch/mips/config.in188
-rw-r--r--arch/mips/dummy.c17
-rw-r--r--arch/mips/entry.S665
-rw-r--r--arch/mips/ioport.c20
-rw-r--r--arch/mips/irq.S642
-rw-r--r--arch/mips/irq.c292
-rw-r--r--arch/mips/kernel/Makefile94
-rw-r--r--arch/mips/kernel/bios32.c7
-rw-r--r--arch/mips/kernel/entry.S625
-rw-r--r--arch/mips/kernel/gdb-low.S300
-rw-r--r--arch/mips/kernel/gdb-stub.c748
-rw-r--r--arch/mips/kernel/head.S412
-rw-r--r--arch/mips/kernel/ioport.c36
-rw-r--r--arch/mips/kernel/irq.c334
-rw-r--r--arch/mips/kernel/jazzdma.c518
-rw-r--r--arch/mips/kernel/magnum4000.S261
-rw-r--r--arch/mips/kernel/pica.S252
-rw-r--r--arch/mips/kernel/process.c216
-rw-r--r--arch/mips/kernel/ptrace.c (renamed from arch/mips/ptrace.c)86
-rw-r--r--arch/mips/kernel/r4xx0.S732
-rw-r--r--arch/mips/kernel/setup.c207
-rw-r--r--arch/mips/kernel/signal.c (renamed from arch/mips/signal.c)267
-rw-r--r--arch/mips/kernel/traps.c438
-rw-r--r--arch/mips/kernel/tyne.S114
-rw-r--r--arch/mips/kernel/tynedma.c36
-rw-r--r--arch/mips/kernel/vm86.c (renamed from arch/mips/vm86.c)0
-rw-r--r--arch/mips/ldt.c13
-rw-r--r--arch/mips/lib/Makefile33
-rw-r--r--arch/mips/lib/dump_tlb.c161
-rw-r--r--arch/mips/lib/tinycon.c133
-rw-r--r--arch/mips/lib/watch.S102
-rw-r--r--arch/mips/main.c333
-rw-r--r--arch/mips/mkdisk5
-rw-r--r--arch/mips/mm/Makefile6
-rw-r--r--arch/mips/mm/fault.c92
-rw-r--r--arch/mips/mm/init.c299
-rw-r--r--arch/mips/mm/kmalloc.c362
-rw-r--r--arch/mips/mm/memory.c1295
-rw-r--r--arch/mips/mm/mmap.c470
-rw-r--r--arch/mips/mm/mprotect.c230
-rw-r--r--arch/mips/mm/swap.c986
-rw-r--r--arch/mips/mm/vmalloc.c202
-rw-r--r--arch/mips/sched.c804
-rw-r--r--arch/mips/splx.c30
-rw-r--r--arch/mips/traps.c135
65 files changed, 9345 insertions, 7238 deletions
diff --git a/arch/mips/.gdbinit b/arch/mips/.gdbinit
new file mode 100644
index 000000000..8bdcdae68
--- /dev/null
+++ b/arch/mips/.gdbinit
@@ -0,0 +1,7 @@
+echo Setting up the environment for debugging vmlinux...\n
+echo set remotedebug 0 \n
+set remotedebug 0
+echo cd arch/mips/kernel \n
+cd arch/mips/kernel
+echo target remote /dev/ttyS0 \n
+target remote /dev/ttyS0
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 0dc133749..baec00d70 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -1,71 +1,101 @@
#
-# Makefile.mips
+# arch/mips/Makefile
+#
+# This file is included by the global makefile so that you can add your own
+# architecture-specific flags and dependencies. Remember to do have actions
+# for "archclean" and "archdep" for cleaning up and making dependencies for
+# this architecture
#
# 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 by Waldorf GMBH,
+# Copyright (C) 1994, 1995 by Waldorf Electronics,
# written by Ralf Baechle
#
-AS = mips-linux-as
-ASFLAGS = -mips3 -mcpu=r4000
-LD = mips-linux-ld
-HOSTCC = gcc
-CC = mips-linux-gcc -V 2.5.8 -Wa,-mips3 -mcpu=r4000 -D__KERNEL__ -I$(TOPDIR)/include
-#CC = mips-linux-gcc -V 2.6.2 -Wa,-mips3 -mcpu=r4600 -D__KERNEL__ -I$(TOPDIR)/include
-MAKE = make
-CPP = $(CC) -E
-AR = mips-linux-ar
-RANLIB = mips-linux-ranlib
-STRIP = strip
-KERNELHDRS = /home/ralf/src/linux
+ifdef CONFIG_ELF_COMPILER
+ifdef CONFIG_CPU_LITTLE_ENDIAN
+prefix = mipsel-linuxelf-
+else
+prefix = mips-linuxelf-
+endif
+else
+ifdef CONFIG_CPU_LITTLE_ENDIAN
+prefix = mipsel-linux-
+else
+prefix = mips-linux-
+endif
+endif
+
+AS = $(prefix)as
+LD = $(prefix)ld
+LINKFLAGS = -N -Ttext 0x80000000
+#HOSTCC = gcc
+CC = $(prefix)gcc -D__KERNEL__ -I$(TOPDIR)/include
+CPP = $(CC) -E $(CFLAGS)
+AR = $(prefix)ar
+RANLIB = $(prefix)ranlib
+STRIP = $(prefix)strip
+NM = $(prefix)nm
+
+#
+# The new ELF GCC uses -G0 -mabicalls -fpic as default. We don't need PIC
+# code in the kernel since it only slows down the whole thing. For the
+# old GCC these options are just the defaults. At some point we might
+# make use of global pointer optimaztions.
+#
+ifdef CONFIG_OBJECT_ELF
+CFLAGS := $(CFLAGS) -G0 -mno-abicalls -fno-pic #-pipe
+endif
+
+ifdef CONFIG_REMOTE_DEBUG
+CFLAGS := $(CFLAGS) -g
+endif
+
+ifdef CONFIG_CPU_R3000
+CFLAGS := $(CFLAGS) -mcpu=r3000 -mips1
+ASFLAGS := $(ASFLAGS) -mcpu=r3000 -mips1
+endif
+ifdef CONFIG_CPU_R6000
+CFLAGS := $(CFLAGS) -mcpu=r6000 -mips2
+ASFLAGS := $(ASFLAGS) -mcpu=r6000 -mips2
+endif
+ifdef CONFIG_CPU_R4X00
+CFLAGS := $(CFLAGS) -D__R4000__ -mcpu=r4400 -mips2
+ASFLAGS := $(ASFLAGS) -mcpu=r4400 -mips2
+endif
+ifdef CONFIG_CPU_R4600
+CFLAGS := $(CFLAGS) -D__R4000__ -mcpu=r4600 -mips2
+ASFLAGS := $(ASFLAGS) -mcpu=r4600 -mips2
+endif
+ifdef CONFIG_CPU_R8000
+CFLAGS := $(CFLAGS) -D__R4000__ -mcpu=r8000 -mips2
+ASFLAGS := $(ASFLAGS) -mcpu=r8000 -mips2
+endif
+ifdef CONFIG_CPU_R10000
+CFLAGS := $(CFLAGS) -D__R4000__ -mcpu=r8000 -mips2
+ASFLAGS := $(ASFLAGS) -mcpu=r8000 -mips2
+endif
+
+HEAD := arch/mips/kernel/head.o
-zBoot/zSystem: zBoot/*.c zBoot/*.S tools/zSystem
- $(MAKE) -C zBoot
+SUBDIRS := $(SUBDIRS) arch/mips/kernel arch/mips/mm arch/mips/lib
+ARCHIVES := arch/mips/kernel/kernel.o arch/mips/mm/mm.o $(ARCHIVES)
+LIBS := arch/mips/lib/lib.a $(LIBS) arch/mips/lib/lib.a
-zImage: $(CONFIGURE) tools/zSystem
- cp tools/System zImage
- sync
+MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
-#zImage: $(CONFIGURE) zBoot/zSystem tools/build
-# tools/build zBoot/zSystem $(ROOT_DEV) > zImage
-# sync
+zImage: vmlinux
+ @$(MAKEBOOT) zImage
-zdisk: zImage
- mcopy -n zImage a:vmlinux
+compressed: zImage
-tools/zSystem: boot/head.o init/main.o init/init.o tools/version.o linuxsubdirs
- $(LD) $(LOWLDFLAGS) boot/head.o init/main.o init/init.o \
- tools/version.o \
- $(ARCHIVES) \
- $(FILESYSTEMS) \
- $(DRIVERS) \
- $(LIBS) \
- -N -Ttext 0x80000000 \
- -o tools/System
- nm tools/System | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)' | \
- sort > System.map
+zdisk: vmlinux
+ @$(MAKEBOOT) zdisk
-#tools/system: boot/head.o init/main.o init/init.o tools/version.o linuxsubdirs
-# $(LD) $(LOWLDFLAGS) boot/head.o init/main.o tools/version.o \
-# $(ARCHIVES) \
-# $(FILESYSTEMS) \
-# $(DRIVERS) \
-# $(LIBS) \
-# -N -Ttext 0x80000000 \
-# -o tools/system
-# nm tools/zSystem | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)' | \
-# sort > System.map
+archclean:
+ @$(MAKEBOOT) clean
-#tools/zSystem: boot/head.o init/main.o tools/version.o linuxsubdirs
-# $(LD) $(HIGHLDFLAGS) boot/head.o init/main.o tools/version.o \
-# $(ARCHIVES) \
-# $(FILESYSTEMS) \
-# $(DRIVERS) \
-# $(LIBS) \
-# -N -Ttext 0x80600000 \
-# -o tools/zSystem
-# nm tools/zSystem | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)' | \
-# sort > zSystem.map
+archdep:
+ @$(MAKEBOOT) dep
diff --git a/arch/mips/TODO b/arch/mips/TODO
new file mode 100644
index 000000000..29afd71f7
--- /dev/null
+++ b/arch/mips/TODO
@@ -0,0 +1,10 @@
+ - Check the definitions for F_EXLCK and F_SHLCK in include/asm-mips/fcntl.h
+ for correctness and compatibility with MIPS ABI.
+ - Check the definitions for O_NDELAY in include/asm-mips/fcntl.h for
+ correctness and compatibility with MIPS ABI.
+ - What are the fields l_sysid and pad in struct flock supposed to contain?
+ Do we need to handle them in the kernel?
+ - Check the resource limits defines in asm-mips/resource.h
+ - Recheck struct stat in asm-mips/stat.h
+ - Use timestruc_t in struct stat in asm/stat.h instead of time_t
+ - cacheflush should check for illegal flags
diff --git a/arch/mips/bios32.c b/arch/mips/bios32.c
deleted file mode 100644
index bb011a852..000000000
--- a/arch/mips/bios32.c
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
- * bios32.c - BIOS32, PCI BIOS functions.
- *
- * Copyright (C) 1994 by Waldorf GMBH,
- * written by Ralf Baechle
- *
- * Just nothing for a MIPS board...
- */
diff --git a/arch/mips/boot/Makefile b/arch/mips/boot/Makefile
new file mode 100644
index 000000000..93784137d
--- /dev/null
+++ b/arch/mips/boot/Makefile
@@ -0,0 +1,47 @@
+#
+# arch/mips/boot/Makefile
+#
+# 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 by Ralf Baechle
+#
+
+.c.s:
+ $(CC) $(CFLAGS) -S $<
+.s.o:
+ $(AS) $(ASFLAGS) -o $*.o $<
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+.S.s:
+ $(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+ $(CC) $(CFLAGS) -c $< -o $*.o
+
+OBJS = milo.o a.out.o
+
+#
+# Fake compressed boot
+#
+zImage: $(CONFIGURE) $(TOPDIR)/vmlinux
+ cp $(TOPDIR)/vmlinux $@
+ $(STRIP) --discard-all $@
+
+zdisk: zImage
+ mcopy -n zImage a:vmlinux
+
+dep:
+ $(CPP) -M *.[cS] > .depend
+
+clean:
+ rm -f zImage
+
+dummy:
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/arch/mips/boot/a.out.c b/arch/mips/boot/a.out.c
new file mode 100644
index 000000000..15515b219
--- /dev/null
+++ b/arch/mips/boot/a.out.c
@@ -0,0 +1,254 @@
+/*
+ * arch/mips/boot/milo.c
+ *
+ * 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 by Ralf Baechle
+ * Copyright (C) 1993 by Hamish Macdonald
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/file.h>
+
+#include "loader.h"
+
+static int kfd;
+static struct exec kexec;
+static off_t filesize;
+static struct nlist *syms;
+static char *strs;
+static long strsize, numsyms;
+
+/*
+ * Read a symbol from the kernel executable
+ */
+static struct nlist *aout_get_nlist(char *symbol)
+{
+ struct nlist *nl, *p = NULL;
+
+ for (nl = syms; nl < syms + numsyms; nl++) {
+ /*
+ * We accept only extern visible .text, .data and .bss symbols.
+ */
+ if (strcmp (symbol, strs + nl->n_un.n_strx) == 0
+ && ((nl->n_type == N_TEXT | N_EXT) ||
+ (nl->n_type == N_DATA | N_EXT) ||
+ (nl->n_type == N_BSS | N_EXT))) {
+ p = (struct nlist *)malloc (sizeof (struct nlist)
+ + strlen(strs + nl->n_un.n_strx) + 1);
+ if (!p)
+ break;
+ *p = *nl;
+ p->n_un.n_name = (char *)(p+1);
+ strcpy (p->n_un.n_name, strs + nl->n_un.n_strx);
+ }
+ }
+ return p;
+}
+
+/*
+ * Return a pointer to the internal symbol
+ */
+static char *aout_ld_isymbol(char *symbol)
+{
+ static char isymbol[64];
+
+ strcpy(isymbol, STR(C_LABEL_PREFIX));
+ strcat(isymbol, symbol);
+
+ return isymbol;
+}
+
+/*
+ * Return base address for the loaded kernel
+ */
+static u_long aout_get_kbase(void)
+{
+ return (u_long) kexec.a_entry;
+}
+
+/*
+ * Return size of kernel code + data
+ */
+static u_long aout_get_ksize(void)
+{
+ return (u_long) (kexec.a_text + kexec.a_data);
+}
+
+/*
+ * Load a.out kernel into memory
+ */
+static int aout_load_kernel(void *mem)
+{
+ if (lseek (kfd, N_TXTOFF(kexec), L_SET) == -1)
+ {
+ fprintf (stderr, "Failed to seek to text\n\r");
+ exit (EXIT_FAILURE);
+ }
+ if (read (kfd, mem, kexec.a_text) != kexec.a_text)
+ {
+ fprintf (stderr, "Failed to read text\n\r");
+ exit (EXIT_FAILURE);
+ }
+ if (lseek (kfd, N_DATOFF(kexec), L_SET) == -1)
+ {
+ fprintf (stderr, "Failed to seek to data\n\r");
+ exit (EXIT_FAILURE);
+ }
+ if (read (kfd, mem + kexec.a_text, kexec.a_data) != kexec.a_data)
+ {
+ fprintf (stderr, "Failed to read data\n\r");
+ exit (EXIT_FAILURE);
+ }
+ close (kfd);
+
+ return 0;
+}
+
+/*
+ * Print some statistics about the kernel
+ */
+static void aout_print_stats(void)
+{
+ printf("Kernel text at 0x%08lx, size %d bytes\n\r",
+ kexec.a_entry + N_TXTADDR(kexec), kexec.a_text);
+ printf("Kernel data at 0x%08lx, size %d bytes\n\r",
+ kexec.a_entry + N_DATADDR(kexec), kexec.a_data );
+ printf("Kernel bss at 0x%08lx, size %d bytes\n\r",
+ kexec.a_entry + N_BSSADDR(kexec), kexec.a_bss );
+}
+
+static int aout_open_kernel(char *kernel)
+{
+ int sfd;
+
+ /*
+ * open kernel executable and read exec header
+ */
+ if (debuglevel >= 2)
+ {
+ printf("aout_open_kernel(): Open kernel file\r\n");
+ fflush(stdout);
+ }
+ if ((kfd = open (kernel, O_RDONLY)) == -1)
+ {
+ printf ("Unable to open kernel file %s\r\n", kernel);
+ exit (EXIT_FAILURE);
+ }
+ if (debuglevel >= 2)
+ {
+ printf("aout_open_kernel(): Reading exec header\r\n");
+ fflush(stdout);
+ }
+ if (read (kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec))
+ {
+ printf ("Unable to read exec header from %s\n\r", kernel);
+ exit (EXIT_FAILURE);
+ }
+
+ /*
+ * Is this really a kernel???
+ * (My Mips docs mention SMAGIC, too, but don't tell about what
+ * a SMAGIC file exactly is. If someone knows, please tell me -Ralf)
+ *
+ * FIXME: QMAGIC doesn't work yet.
+ */
+ if(N_MAGIC(kexec) != OMAGIC &&
+ N_MAGIC(kexec) != NMAGIC &&
+ N_MAGIC(kexec) != ZMAGIC &&
+ N_MAGIC(kexec) != QMAGIC)
+ {
+ fprintf(stderr, "Kernel %s is no MIPS binary.\r\n", kernel);
+ exit (EXIT_FAILURE);
+ }
+ if(N_MACHTYPE(kexec) != M_MIPS1 &&
+ N_MACHTYPE(kexec) != M_MIPS2)
+ {
+ fprintf(stderr, "Kernel %s is no MIPS binary.\r\n", kernel);
+ exit (EXIT_FAILURE);
+ }
+
+ /*
+ * Read file's symbol table
+ */
+ /*
+ * Open kernel executable and read exec header - we need to
+ * use a second open file since the ARC standard doesn't
+ * support reverse seeking on files which might run us in
+ * trouble later on.
+ */
+ if (debuglevel >= 2)
+ {
+ printf("aout_open_kernel(): Open kernel file\r\n");
+ fflush(stdout);
+ }
+ if ((sfd = open (kernel, O_RDONLY)) == -1)
+ {
+ printf ("Unable to open kernel %s for reading symbols.\r\n", kernel);
+ exit (EXIT_FAILURE);
+ }
+ syms = (struct nlist *)malloc (kexec.a_syms);
+ if (!syms)
+ {
+ return 0;
+ }
+
+ if (debuglevel >= 2)
+ {
+ printf("aout_open_kernel(): Seeking to symbol table\r\n");
+ fflush(stdout);
+ }
+ lseek (sfd, N_SYMOFF(kexec), L_SET);
+ if (debuglevel >= 2)
+ {
+ printf("aout_open_kernel(): Reading symbol table\r\n");
+ fflush(stdout);
+ }
+ read (sfd, syms, kexec.a_syms);
+ numsyms = kexec.a_syms / sizeof (struct nlist);
+ filesize = lseek (sfd, 0L, L_XTND);
+ strsize = filesize - N_STROFF(kexec);
+ strs = (char *)malloc (strsize);
+
+ if (!strs)
+ {
+ free (syms);
+ syms = NULL;
+ return 0;
+ }
+
+ lseek (sfd, N_STROFF(kexec), L_SET);
+ read (sfd, strs, strsize);
+ close(sfd);
+
+ return 0;
+}
+
+static void aout_close_kernel(void)
+{
+ if (strs)
+ {
+ free (strs);
+ strs = NULL;
+ }
+ if (syms)
+ {
+ free (syms);
+ syms = NULL;
+ }
+ close(kfd);
+}
+
+struct loader loader_aout = {
+ aout_get_nlist,
+ aout_ld_isymbol,
+ aout_get_kbase,
+ aout_get_ksize,
+ aout_load_kernel,
+ aout_print_stats,
+ aout_open_kernel,
+ aout_close_kernel
+};
diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile
new file mode 100644
index 000000000..228ee83bc
--- /dev/null
+++ b/arch/mips/boot/compressed/Makefile
@@ -0,0 +1,45 @@
+#
+# linux/arch/i386/boot/compressed/Makefile
+#
+# create a compressed vmlinux image from the original vmlinux
+#
+
+HEAD = head.o
+SYSTEM = $(TOPDIR)/vmlinux
+
+OBJECTS = $(HEAD) inflate.o unzip.o misc.o
+
+CFLAGS = -O2 -DSTDC_HEADERS
+
+.c.s:
+ $(CC) $(CFLAGS) -S $<
+.s.o:
+ $(AS) $(ASFLAGS) -o $*.o $<
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+.S.s:
+ $(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+ $(CC) $(CFLAGS) -c $< -o $*.o
+
+all: vmlinux
+
+vmlinux: piggy.o $(OBJECTS)
+ $(LD) $(ZLINKFLAGS) -o vmlinux $(OBJECTS) piggy.o
+
+head.o: head.s
+
+head.s: head.S $(TOPDIR)/include/linux/tasks.h
+ $(CPP) -traditional head.S -o head.s
+
+piggy.o: $(SYSTEM) xtract piggyback
+ ./xtract $(SYSTEM) | gzip -9 | ./piggyback > piggy.o
+
+xtract: xtract.c
+ $(HOSTCC) $(CFLAGS) -o xtract xtract.c
+
+piggyback: piggyback.c
+ $(HOSTCC) $(CFLAGS) -o piggyback piggyback.c
+
+clean:
+ rm -f xtract piggyback vmlinux
diff --git a/arch/mips/boot/compressed/cache.S b/arch/mips/boot/compressed/cache.S
new file mode 100644
index 000000000..8e7fff0c1
--- /dev/null
+++ b/arch/mips/boot/compressed/cache.S
@@ -0,0 +1,162 @@
+/*
+ * arch/mips/boot/compressed/cache.S
+ *
+ * Copyright (C) 1994, 1995 Waldorf Electronics
+ * Written by Ralf Baechle
+ *
+ * Flush instruction/data caches
+ *
+ * Parameters: a0 - starting address to flush
+ * a1 - size of area to be flushed
+ * a2 - which caches to be flushed
+ *
+ * FIXME: - ignores parameters in a0/a1
+ * - doesn't know about second level caches
+ */
+#include <linux/autoconf.h>
+
+#include <asm/asm.h>
+#include <asm/cachectl.h>
+#include <asm/mipsregs.h>
+#include <asm/segment.h>
+
+#ifdef __R4000__
+
+/*
+ * Some bits in the config register
+ */
+#define CONFIG_IB (1<<5)
+#define CONFIG_DB (1<<4)
+
+ /*
+ * Flush instruction/data caches
+ *
+ * Parameters: a0 - starting address to flush
+ * a1 - size of area to be flushed
+ * a2 - which caches to be flushed
+ *
+ */
+
+ .text
+
+ .set noreorder
+ LEAF(cacheflush)
+ andi t1,a2,DCACHE
+ beqz t1,do_icache
+ li t0,KSEG0 # delay slot
+
+ /*
+ * Writeback data cache, even lines
+ */
+ li t1,CACHELINES-1
+1: cache Index_Writeback_Inv_D,0(t0)
+ cache Index_Writeback_Inv_D,32(t0)
+ cache Index_Writeback_Inv_D,64(t0)
+ cache Index_Writeback_Inv_D,96(t0)
+ cache Index_Writeback_Inv_D,128(t0)
+ cache Index_Writeback_Inv_D,160(t0)
+ cache Index_Writeback_Inv_D,192(t0)
+ cache Index_Writeback_Inv_D,224(t0)
+ cache Index_Writeback_Inv_D,256(t0)
+ cache Index_Writeback_Inv_D,288(t0)
+ cache Index_Writeback_Inv_D,320(t0)
+ cache Index_Writeback_Inv_D,352(t0)
+ cache Index_Writeback_Inv_D,384(t0)
+ cache Index_Writeback_Inv_D,416(t0)
+ cache Index_Writeback_Inv_D,448(t0)
+ cache Index_Writeback_Inv_D,480(t0)
+ addiu t0,512
+ bnez t1,1b
+ subu t1,1
+
+ /*
+ * Writeback data cache, odd lines
+ * Only needed for 16 byte line size
+ */
+ mfc0 t1,CP0_CONFIG
+ andi t1,CONFIG_IB
+ bnez t1,do_icache
+ li t1,CACHELINES-1
+1: cache Index_Writeback_Inv_D,16(t0)
+ cache Index_Writeback_Inv_D,48(t0)
+ cache Index_Writeback_Inv_D,80(t0)
+ cache Index_Writeback_Inv_D,112(t0)
+ cache Index_Writeback_Inv_D,144(t0)
+ cache Index_Writeback_Inv_D,176(t0)
+ cache Index_Writeback_Inv_D,208(t0)
+ cache Index_Writeback_Inv_D,240(t0)
+ cache Index_Writeback_Inv_D,272(t0)
+ cache Index_Writeback_Inv_D,304(t0)
+ cache Index_Writeback_Inv_D,336(t0)
+ cache Index_Writeback_Inv_D,368(t0)
+ cache Index_Writeback_Inv_D,400(t0)
+ cache Index_Writeback_Inv_D,432(t0)
+ cache Index_Writeback_Inv_D,464(t0)
+ cache Index_Writeback_Inv_D,496(t0)
+ addiu t0,512
+ bnez t1,1b
+ subu t1,1
+
+do_icache: andi t1,a2,ICACHE
+ beqz t1,done
+
+ /*
+ * Flush instruction cache, even lines
+ */
+ lui t0,0x8000
+ li t1,CACHELINES-1
+1: cache Index_Invalidate_I,0(t0)
+ cache Index_Invalidate_I,32(t0)
+ cache Index_Invalidate_I,64(t0)
+ cache Index_Invalidate_I,96(t0)
+ cache Index_Invalidate_I,128(t0)
+ cache Index_Invalidate_I,160(t0)
+ cache Index_Invalidate_I,192(t0)
+ cache Index_Invalidate_I,224(t0)
+ cache Index_Invalidate_I,256(t0)
+ cache Index_Invalidate_I,288(t0)
+ cache Index_Invalidate_I,320(t0)
+ cache Index_Invalidate_I,352(t0)
+ cache Index_Invalidate_I,384(t0)
+ cache Index_Invalidate_I,416(t0)
+ cache Index_Invalidate_I,448(t0)
+ cache Index_Invalidate_I,480(t0)
+ addiu t0,512
+ bnez t1,1b
+ subu t1,1
+
+ /*
+ * Flush instruction cache, even lines
+ * Only needed for 16 byte line size
+ */
+ mfc0 t1,CP0_CONFIG
+ andi t1,CONFIG_DB
+ bnez t1,done
+ li t1,CACHELINES-1
+1: cache Index_Invalidate_I,16(t0)
+ cache Index_Invalidate_I,48(t0)
+ cache Index_Invalidate_I,80(t0)
+ cache Index_Invalidate_I,112(t0)
+ cache Index_Invalidate_I,144(t0)
+ cache Index_Invalidate_I,176(t0)
+ cache Index_Invalidate_I,208(t0)
+ cache Index_Invalidate_I,240(t0)
+ cache Index_Invalidate_I,272(t0)
+ cache Index_Invalidate_I,304(t0)
+ cache Index_Invalidate_I,336(t0)
+ cache Index_Invalidate_I,368(t0)
+ cache Index_Invalidate_I,400(t0)
+ cache Index_Invalidate_I,432(t0)
+ cache Index_Invalidate_I,464(t0)
+ cache Index_Invalidate_I,496(t0)
+ addiu t0,512
+ bnez t1,1b
+ subu t1,1
+
+done: j ra
+ nop
+ END(sys_cacheflush)
+
+#else /* !defined (__R4000__) */
+#error "No R3000 cacheflushing implemented yet!"
+#endif /* !defined (__R4000__) */
diff --git a/arch/mips/boot/compressed/crypt.h b/arch/mips/boot/compressed/crypt.h
new file mode 100644
index 000000000..2a4c203ca
--- /dev/null
+++ b/arch/mips/boot/compressed/crypt.h
@@ -0,0 +1,12 @@
+/* crypt.h (dummy version) -- do not perform encryption
+ * Hardly worth copyrighting :-)
+ */
+
+#ifdef CRYPT
+# undef CRYPT /* dummy version */
+#endif
+
+#define RAND_HEAD_LEN 12 /* length of encryption random header */
+
+#define zencode
+#define zdecode
diff --git a/arch/mips/boot/compressed/gzip.h b/arch/mips/boot/compressed/gzip.h
new file mode 100644
index 000000000..2f738b945
--- /dev/null
+++ b/arch/mips/boot/compressed/gzip.h
@@ -0,0 +1,284 @@
+/* gzip.h -- common declarations for all gzip modules
+ * Copyright (C) 1992-1993 Jean-loup Gailly.
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#if defined(__STDC__) || defined(PROTO)
+# define OF(args) args
+#else
+# define OF(args) ()
+#endif
+
+#ifdef __STDC__
+ typedef void *voidp;
+#else
+ typedef char *voidp;
+#endif
+
+/* I don't like nested includes, but the string functions are used too often */
+#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
+# include <string.h>
+# define memzero(s, n) memset ((s), 0, (n))
+#else
+# include <strings.h>
+# define strchr index
+# define strrchr rindex
+# define memcpy(d, s, n) bcopy((s), (d), (n))
+# define memcmp(s1, s2, n) bcmp((s1), (s2), (n))
+# define memzero(s, n) bzero((s), (n))
+#endif
+
+#if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H)
+# include <memory.h>
+#endif
+
+#ifndef RETSIGTYPE
+# define RETSIGTYPE void
+#endif
+
+#define local static
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned long ulg;
+
+/* Return codes from gzip */
+#define OK 0
+#define ERROR 1
+#define WARNING 2
+
+/* Compression methods (see algorithm.doc) */
+#define STORED 0
+#define COMPRESSED 1
+#define PACKED 2
+/* methods 3 to 7 reserved */
+#define DEFLATED 8
+extern int method; /* compression method */
+
+/* To save memory for 16 bit systems, some arrays are overlayed between
+ * the various modules:
+ * deflate: prev+head window d_buf l_buf outbuf
+ * unlzw: tab_prefix tab_suffix stack inbuf outbuf
+ * inflate: window inbuf
+ * unpack: window inbuf
+ * For compression, input is done in window[]. For decompression, output
+ * is done in window except for unlzw.
+ */
+
+#ifndef INBUFSIZ
+# define INBUFSIZ 0x8000 /* input buffer size */
+#endif
+#define INBUF_EXTRA 64 /* required by unlzw() */
+
+#ifndef OUTBUFSIZ
+# define OUTBUFSIZ 16384 /* output buffer size */
+#endif
+#define OUTBUF_EXTRA 2048 /* required by unlzw() */
+
+#define DIST_BUFSIZE 0x8000 /* buffer for distances, see trees.c */
+
+#ifdef DYN_ALLOC
+# define EXTERN(type, array) extern type * near array
+# define DECLARE(type, array, size) type * near array
+# define ALLOC(type, array, size) { \
+ array = (type*)fcalloc((unsigned)(((size)+1L)/2), 2*sizeof(type)); \
+ if (array == NULL) error("insufficient memory"); \
+ }
+# define FREE(array) {if (array != NULL) fcfree(array), array=NULL;}
+#else
+# define EXTERN(type, array) extern type array[]
+# define DECLARE(type, array, size) type array[size]
+# define ALLOC(type, array, size)
+# define FREE(array)
+#endif
+
+EXTERN(uch, inbuf); /* input buffer */
+EXTERN(uch, outbuf); /* output buffer */
+EXTERN(ush, d_buf); /* buffer for distances, see trees.c */
+EXTERN(uch, window); /* Sliding window and suffix table (unlzw) */
+#define tab_suffix window
+#ifndef MAXSEG_64K
+# define tab_prefix prev /* hash link (see deflate.c) */
+# define head (prev+WSIZE) /* hash head (see deflate.c) */
+ EXTERN(ush, tab_prefix); /* prefix code (see unlzw.c) */
+#else
+# define tab_prefix0 prev
+# define head tab_prefix1
+ EXTERN(ush, tab_prefix0); /* prefix for even codes */
+ EXTERN(ush, tab_prefix1); /* prefix for odd codes */
+#endif
+
+extern unsigned insize; /* valid bytes in inbuf */
+extern unsigned inptr; /* index of next byte to be processed in inbuf */
+extern unsigned outcnt; /* bytes in output buffer */
+
+extern long bytes_in; /* number of input bytes */
+extern long bytes_out; /* number of output bytes */
+extern long overhead; /* number of bytes in gzip header */
+
+#define isize bytes_in
+/* for compatibility with old zip sources (to be cleaned) */
+
+extern int ifd; /* input file descriptor */
+extern int ofd; /* output file descriptor */
+extern char ifname[]; /* input filename or "stdin" */
+extern char ofname[]; /* output filename or "stdout" */
+
+extern ulg time_stamp; /* original time stamp (modification time) */
+extern long ifile_size; /* input file size, -1 for devices (debug only) */
+
+extern int exit_code; /* program exit code */
+
+typedef int file_t; /* Do not use stdio */
+#define NO_FILE (-1) /* in memory compression */
+
+
+#define GZIP_MAGIC "\037\213" /* Magic header for gzip files, 1F 8B */
+#define OLD_GZIP_MAGIC "\037\236" /* Magic header for gzip 0.5 = freeze 1.x */
+#define PKZIP_MAGIC "PK\003\004" /* Magic header for pkzip files */
+#define PACK_MAGIC "\037\036" /* Magic header for packed files */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
+#define RESERVED 0xC0 /* bit 6,7: reserved */
+
+/* internal file attribute */
+#define UNKNOWN (-1)
+#define BINARY 0
+#define ASCII 1
+
+#ifndef WSIZE
+# define WSIZE 0x8000 /* window size--must be a power of two, and */
+#endif /* at least 32K for zip's deflate method */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST (WSIZE-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+extern int decrypt; /* flag to turn on decryption */
+extern int save_orig_name; /* set if original name must be saved */
+extern int verbose; /* be verbose (-v) */
+extern int level; /* compression level */
+extern int test; /* check .z file integrity */
+extern int to_stdout; /* output to stdout (-c) */
+
+#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
+
+/* put_byte is used for the compressed output, put_char for the
+ * uncompressed output. However unlzw() uses window for its
+ * suffix table instead of its output buffer, so it does not use put_char.
+ * (to be cleaned up).
+ */
+#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\
+ flush_outbuf();}
+#define put_char(c) {window[outcnt++]=(uch)(c); if (outcnt==WSIZE)\
+ flush_window();}
+
+/* Output a 16 bit value, lsb first */
+#define put_short(w) \
+{ if (outcnt < OUTBUFSIZ-2) { \
+ outbuf[outcnt++] = (uch) ((w) & 0xff); \
+ outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \
+ } else { \
+ put_byte((uch)((w) & 0xff)); \
+ put_byte((uch)((ush)(w) >> 8)); \
+ } \
+}
+
+/* Output a 32 bit value to the bit stream, lsb first */
+#define put_long(n) { \
+ put_short((n) & 0xffff); \
+ put_short(((ulg)(n)) >> 16); \
+}
+
+#define seekable() 0 /* force sequential output */
+#define translate_eol 0 /* no option -a yet */
+
+#define tolow(c) (isupper(c) ? (c)-'A'+'a' : (c)) /* force to lower case */
+
+/* Macros for getting two-byte and four-byte header values */
+#define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8))
+#define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16))
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# define Assert(cond,msg) {if(!(cond)) error(msg);}
+# define Trace(x) fprintf x
+# define Tracev(x) {if (verbose) fprintf x ;}
+# define Tracevv(x) {if (verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+ /* in zip.c: */
+extern void zip OF((int in, int out));
+extern int file_read OF((char *buf, unsigned size));
+
+ /* in unzip.c */
+extern void unzip OF((int in, int out));
+extern int check_zipfile OF((int in));
+
+ /* in unpack.c */
+extern void unpack OF((int in, int out));
+
+ /* in gzip.c */
+RETSIGTYPE abort_gzip OF((void));
+
+ /* in deflate.c */
+void lm_init OF((int pack_level, ush *flags));
+ulg deflate OF((void));
+
+ /* in trees.c */
+void ct_init OF((ush *attr, int *method));
+int ct_tally OF((int dist, int lc));
+ulg flush_block OF((char *buf, ulg stored_len, int eof));
+
+ /* in bits.c */
+void bi_init OF((file_t zipfile));
+void send_bits OF((int value, int length));
+unsigned bi_reverse OF((unsigned value, int length));
+void bi_windup OF((void));
+void copy_block OF((char *buf, unsigned len, int header));
+extern int (*read_buf) OF((char *buf, unsigned size));
+
+ /* in util.c: */
+extern ulg updcrc OF((uch *s, unsigned n));
+extern void clear_bufs OF((void));
+extern int fill_inbuf OF((void));
+extern void flush_outbuf OF((void));
+extern void flush_window OF((void));
+extern char *strlwr OF((char *s));
+extern char *basename OF((char *fname));
+extern char *add_envopt OF((int *argcp, char ***argvp, char *env));
+extern void error OF((char *m));
+extern void warn OF((char *a, char *b));
+extern void read_error OF((void));
+extern void write_error OF((void));
+extern void display_ratio OF((long num, long den));
+extern voidp xmalloc OF((unsigned int size));
+
+ /* in inflate.c */
+extern int inflate OF((void));
diff --git a/arch/mips/boot/compressed/head.S b/arch/mips/boot/compressed/head.S
new file mode 100644
index 000000000..0ca599563
--- /dev/null
+++ b/arch/mips/boot/compressed/head.S
@@ -0,0 +1,52 @@
+/*
+ * arch/mips/boot/compressed/head.S
+ *
+ * Copyright (C) 1995 by Ralf Baechle
+ *
+ * Head.S contains the MIPS exception handler and startup code.
+ */
+
+#include <asm/asm.h>
+
+ .text
+ .set noreorder
+/*
+ * Compressed kernel entry
+ */
+ NESTED(kernel_entry, 16, sp)
+ /*
+ * Set EXL in c0_status. The results in the lowest two
+ * gigabytes identity mapped.
+ */
+ mfc0 t0,CP0_STATUS
+ ori t0,4
+ mtc0 t0,CP0_STATUS
+
+ /*
+ * Clear BSS first so that there are no surprises...
+ */
+ la t0,_edata
+ la t1,_end
+ sw zero,(t0)
+1: addiu t0,4
+ bnel t0,t1,1b
+ sw zero,(t0)
+ END(kernel_entry)
+
+ /*
+ * Do the decompression, and jump to the new kernel..
+ */
+ jal C_LABEL(decompress_kernel)
+ nop
+
+ /*
+ * Flush caches
+ */
+ jal C_LABEL(cacheflush)
+
+ /*
+ * Jump into the decompressed kernel
+ */
+ la t0,KSEG0
+ jr t0
+ nop
diff --git a/arch/mips/boot/compressed/inflate.c b/arch/mips/boot/compressed/inflate.c
new file mode 100644
index 000000000..848fef6ae
--- /dev/null
+++ b/arch/mips/boot/compressed/inflate.c
@@ -0,0 +1,810 @@
+#define DEBG(x)
+#define DEBG1(x)
+/* inflate.c -- Not copyrighted 1992 by Mark Adler
+ version c10p1, 10 January 1993 */
+
+/*
+ * Adapted for booting Linux by Hannu Savolainen 1993
+ * based on gzip-1.0.3
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: inflate.c,v 0.10 1993/02/04 13:21:06 jloup Exp $";
+#endif
+
+#include "gzip.h"
+#define slide window
+
+#if defined(STDC_HEADERS) || defined(HAVE_STDLIB_H)
+# include <sys/types.h>
+# include <stdlib.h>
+#endif
+
+struct huft {
+ uch e; /* number of extra bits or operation */
+ uch b; /* number of bits in this code or subcode */
+ union {
+ ush n; /* literal, length base, or distance base */
+ struct huft *t; /* pointer to next level of table */
+ } v;
+};
+
+
+/* Function prototypes */
+int huft_build OF((unsigned *, unsigned, unsigned, ush *, ush *,
+ struct huft **, int *));
+int huft_free OF((struct huft *));
+int inflate_codes OF((struct huft *, struct huft *, int, int));
+int inflate_stored OF((void));
+int inflate_fixed OF((void));
+int inflate_dynamic OF((void));
+int inflate_block OF((int *));
+int inflate OF((void));
+
+
+#define wp outcnt
+#define flush_output(w) (wp=(w),flush_window())
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+static unsigned border[] = { /* Order of the bit length code lengths */
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+static ush cplens[] = { /* Copy lengths for literal codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ /* note: see note #13 above about the 258 in this list. */
+static ush cplext[] = { /* Extra bits for literal codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */
+static ush cpdist[] = { /* Copy offsets for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577};
+static ush cpdext[] = { /* Extra bits for distance codes */
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13};
+
+
+ulg bb; /* bit buffer */
+unsigned bk; /* bits in bit buffer */
+
+ush mask_bits[] = {
+ 0x0000,
+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+#ifdef CRYPT
+ uch cc;
+# define NEXTBYTE() \
+ (decrypt ? (cc = get_byte(), zdecode(cc), cc) : get_byte())
+#else
+# define NEXTBYTE() (uch)get_byte()
+#endif
+#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}}
+#define DUMPBITS(n) {b>>=(n);k-=(n);}
+
+int lbits = 9; /* bits in base literal/length lookup table */
+int dbits = 6; /* bits in base distance lookup table */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
+#define BMAX 16 /* maximum bit length of any code (16 for explode) */
+#define N_MAX 288 /* maximum number of codes in any set */
+
+
+unsigned hufts; /* track memory usage */
+
+
+int huft_build(b, n, s, d, e, t, m)
+unsigned *b; /* code lengths in bits (all assumed <= BMAX) */
+unsigned n; /* number of codes (assumed <= N_MAX) */
+unsigned s; /* number of simple-valued codes (0..s-1) */
+ush *d; /* list of base values for non-simple codes */
+ush *e; /* list of extra bits for non-simple codes */
+struct huft **t; /* result: starting table */
+int *m; /* maximum lookup bits, returns actual */
+/* Given a list of code lengths and a maximum table size, make a set of
+ tables to decode that set of codes. Return zero on success, one if
+ the given code set is incomplete (the tables are still built in this
+ case), two if the input is invalid (all zero length codes or an
+ oversubscribed set of lengths), and three if not enough memory. */
+{
+ unsigned a; /* counter for codes of length k */
+ unsigned c[BMAX+1]; /* bit length count table */
+ unsigned f; /* i repeats in table every f entries */
+ int g; /* maximum code length */
+ int h; /* table level */
+ register unsigned i; /* counter, current code */
+ register unsigned j; /* counter */
+ register int k; /* number of bits in current code */
+ int l; /* bits per table (returned in m) */
+ register unsigned *p; /* pointer into c[], b[], or v[] */
+ register struct huft *q; /* points to current table */
+ struct huft r; /* table entry for structure assignment */
+ struct huft *u[BMAX]; /* table stack */
+ unsigned v[N_MAX]; /* values in order of bit length */
+ register int w; /* bits before this table == (l * h) */
+ unsigned x[BMAX+1]; /* bit offsets, then code stack */
+ unsigned *xp; /* pointer into x */
+ int y; /* number of dummy codes added */
+ unsigned z; /* number of entries in current table */
+
+DEBG("huft1 ");
+
+ /* Generate counts for each bit length */
+ memzero(c, sizeof(c));
+ p = b; i = n;
+ do {
+ c[*p++]++; /* assume all entries <= BMAX */
+ } while (--i);
+ if (c[0] == n) /* null input--all zero length codes */
+ {
+ *t = (struct huft *)NULL;
+ *m = 0;
+ return 0;
+ }
+
+DEBG("huft2 ");
+
+ /* Find minimum and maximum length, bound *m by those */
+ l = *m;
+ for (j = 1; j <= BMAX; j++)
+ if (c[j])
+ break;
+ k = j; /* minimum code length */
+ if ((unsigned)l < j)
+ l = j;
+ for (i = BMAX; i; i--)
+ if (c[i])
+ break;
+ g = i; /* maximum code length */
+ if ((unsigned)l > i)
+ l = i;
+ *m = l;
+
+DEBG("huft3 ");
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << j; j < i; j++, y <<= 1)
+ if ((y -= c[j]) < 0)
+ return 2; /* bad input: more codes than bits */
+ if ((y -= c[i]) < 0)
+ return 2;
+ c[i] += y;
+
+DEBG("huft4 ");
+
+ /* Generate starting offsets into the value table for each length */
+ x[1] = j = 0;
+ p = c + 1; xp = x + 2;
+ while (--i) { /* note that i == g from above */
+ *xp++ = (j += *p++);
+ }
+
+DEBG("huft5 ");
+
+ /* Make a table of values in order of bit lengths */
+ p = b; i = 0;
+ do {
+ if ((j = *p++) != 0)
+ v[x[j]++] = i;
+ } while (++i < n);
+
+DEBG("h6 ");
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ x[0] = i = 0; /* first Huffman code is zero */
+ p = v; /* grab values in bit order */
+ h = -1; /* no tables yet--level -1 */
+ w = -l; /* bits decoded == (l * h) */
+ u[0] = (struct huft *)NULL; /* just to keep compilers happy */
+ q = (struct huft *)NULL; /* ditto */
+ z = 0; /* ditto */
+DEBG("h6a ");
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++)
+ {
+DEBG("h6b ");
+ a = c[k];
+ while (a--)
+ {
+DEBG("h6b1 ");
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > w + l)
+ {
+DEBG1("1 ");
+ h++;
+ w += l; /* previous table always l bits */
+
+ /* compute minimum size table less than or equal to l bits */
+ z = (z = g - w) > (unsigned)l ? l : z; /* upper limit on table size */
+ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
+ { /* too few codes for k-w bit table */
+DEBG1("2 ");
+ f -= a + 1; /* deduct codes from patterns left */
+ xp = c + k;
+ while (++j < z) /* try smaller tables up to z bits */
+ {
+ if ((f <<= 1) <= *++xp)
+ break; /* enough codes to use up j bits */
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+DEBG1("3 ");
+ z = 1 << j; /* table entries for j-bit table */
+
+ /* allocate and link in new table */
+ q = (struct huft *)malloc((z + 1)*sizeof(struct huft));
+DEBG1("4 ");
+ hufts += z + 1; /* track memory usage */
+ *t = q + 1; /* link to list for huft_free() */
+ *(t = &(q->v.t)) = (struct huft *)NULL;
+ u[h] = ++q; /* table starts after link */
+
+DEBG1("5 ");
+ /* connect to last table, if there is one */
+ if (h)
+ {
+ x[h] = i; /* save pattern for backing up */
+ r.b = (uch)l; /* bits to dump before this table */
+ r.e = (uch)(16 + j); /* bits in this table */
+ r.v.t = q; /* pointer to this table */
+ j = i >> (w - l); /* (get around Turbo C bug) */
+ u[h-1][j] = r; /* connect to last table */
+ }
+DEBG1("6 ");
+ }
+DEBG("h6c ");
+
+ /* set up table entry in r */
+ r.b = (uch)(k - w);
+ if (p >= v + n)
+ r.e = 99; /* out of values--invalid code */
+ else if (*p < s)
+ {
+ r.e = (uch)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */
+ r.v.n = *p++; /* simple code is just the value */
+ }
+ else
+ {
+ r.e = (uch)e[*p - s]; /* non-simple--look up in lists */
+ r.v.n = d[*p++ - s];
+ }
+DEBG("h6d ");
+
+ /* fill code-like entries with r */
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f)
+ q[j] = r;
+
+ /* backwards increment the k-bit code i */
+ for (j = 1 << (k - 1); i & j; j >>= 1)
+ i ^= j;
+ i ^= j;
+
+ /* backup over finished tables */
+ while ((i & ((1 << w) - 1)) != x[h])
+ {
+ h--; /* don't need to update q */
+ w -= l;
+ }
+DEBG("h6e ");
+ }
+DEBG("h6f ");
+ }
+
+DEBG("huft7 ");
+
+ /* Return true (1) if we were given an incomplete table */
+ return y != 0 && g != 1;
+}
+
+
+
+int huft_free(t)
+struct huft *t; /* table to free */
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+ list of the tables it made, with the links in a dummy first entry of
+ each table. */
+{
+ register struct huft *p, *q;
+
+
+ /* Go through linked list, freeing from the malloced (t[-1]) address. */
+ p = t;
+ while (p != (struct huft *)NULL)
+ {
+ q = (--p)->v.t;
+ free(p);
+ p = q;
+ }
+ return 0;
+}
+
+
+int inflate_codes(tl, td, bl, bd)
+struct huft *tl, *td; /* literal/length and distance decoder tables */
+int bl, bd; /* number of bits decoded by tl[] and td[] */
+/* inflate (decompress) the codes in a deflated (compressed) block.
+ Return an error code or zero if it all goes ok. */
+{
+ register unsigned e; /* table entry flag/number of extra bits */
+ unsigned n, d; /* length and index for copy */
+ unsigned w; /* current window position */
+ struct huft *t; /* pointer to table entry */
+ unsigned ml, md; /* masks for bl and bd bits */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+
+ /* make local copies of globals */
+ b = bb; /* initialize bit buffer */
+ k = bk;
+ w = wp; /* initialize window position */
+
+ /* inflate the coded data */
+ ml = mask_bits[bl]; /* precompute masks for speed */
+ md = mask_bits[bd];
+ for (;;) /* do until end of block */
+ {
+ NEEDBITS((unsigned)bl)
+ if ((e = (t = tl + ((unsigned)b & ml))->e) > 16)
+ do {
+ if (e == 99)
+ return 1;
+ DUMPBITS(t->b)
+ e -= 16;
+ NEEDBITS(e)
+ } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+ DUMPBITS(t->b)
+ if (e == 16) /* then it's a literal */
+ {
+ slide[w++] = (uch)t->v.n;
+ if (w == WSIZE)
+ {
+ flush_output(w);
+ w = 0;
+ }
+ }
+ else /* it's an EOB or a length */
+ {
+ /* exit if end of block */
+ if (e == 15)
+ break;
+
+ /* get length of block to copy */
+ NEEDBITS(e)
+ n = t->v.n + ((unsigned)b & mask_bits[e]);
+ DUMPBITS(e);
+
+ /* decode distance of block to copy */
+ NEEDBITS((unsigned)bd)
+ if ((e = (t = td + ((unsigned)b & md))->e) > 16)
+ do {
+ if (e == 99)
+ return 1;
+ DUMPBITS(t->b)
+ e -= 16;
+ NEEDBITS(e)
+ } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+ DUMPBITS(t->b)
+ NEEDBITS(e)
+ d = w - t->v.n - ((unsigned)b & mask_bits[e]);
+ DUMPBITS(e)
+
+ /* do the copy */
+ do {
+ n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e);
+#if !defined(NOMEMCPY) && !defined(DEBUG)
+ if (w - d >= e) /* (this test assumes unsigned comparison) */
+ {
+ memcpy(slide + w, slide + d, e);
+ w += e;
+ d += e;
+ }
+ else /* do it slow to avoid memcpy() overlap */
+#endif /* !NOMEMCPY */
+ do {
+ slide[w++] = slide[d++];
+ } while (--e);
+ if (w == WSIZE)
+ {
+ flush_output(w);
+ w = 0;
+ }
+ } while (n);
+ }
+ }
+
+
+ /* restore the globals from the locals */
+ wp = w; /* restore global window pointer */
+ bb = b; /* restore global bit buffer */
+ bk = k;
+
+ /* done */
+ return 0;
+}
+
+
+
+int inflate_stored()
+/* "decompress" an inflated type 0 (stored) block. */
+{
+ unsigned n; /* number of bytes in block */
+ unsigned w; /* current window position */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+DEBG("<stor");
+
+ /* make local copies of globals */
+ b = bb; /* initialize bit buffer */
+ k = bk;
+ w = wp; /* initialize window position */
+
+
+ /* go to byte boundary */
+ n = k & 7;
+ DUMPBITS(n);
+
+
+ /* get the length and its complement */
+ NEEDBITS(16)
+ n = ((unsigned)b & 0xffff);
+ DUMPBITS(16)
+ NEEDBITS(16)
+ if (n != (unsigned)((~b) & 0xffff))
+ return 1; /* error in compressed data */
+ DUMPBITS(16)
+
+
+ /* read and output the compressed data */
+ while (n--)
+ {
+ NEEDBITS(8)
+ slide[w++] = (uch)b;
+ if (w == WSIZE)
+ {
+ flush_output(w);
+ w = 0;
+ }
+ DUMPBITS(8)
+ }
+
+
+ /* restore the globals from the locals */
+ wp = w; /* restore global window pointer */
+ bb = b; /* restore global bit buffer */
+ bk = k;
+
+ DEBG(">");
+ return 0;
+}
+
+
+
+int inflate_fixed()
+/* decompress an inflated type 1 (fixed Huffman codes) block. We should
+ either replace this with a custom decoder, or at least precompute the
+ Huffman tables. */
+{
+ int i; /* temporary variable */
+ struct huft *tl; /* literal/length code table */
+ struct huft *td; /* distance code table */
+ int bl; /* lookup bits for tl */
+ int bd; /* lookup bits for td */
+ unsigned l[288]; /* length list for huft_build */
+
+DEBG("<fix");
+
+ /* set up literal table */
+ for (i = 0; i < 144; i++)
+ l[i] = 8;
+ for (; i < 256; i++)
+ l[i] = 9;
+ for (; i < 280; i++)
+ l[i] = 7;
+ for (; i < 288; i++) /* make a complete, but wrong code set */
+ l[i] = 8;
+ bl = 7;
+ if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0)
+ return i;
+
+
+ /* set up distance table */
+ for (i = 0; i < 30; i++) /* make an incomplete code set */
+ l[i] = 5;
+ bd = 5;
+ if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1)
+ {
+ huft_free(tl);
+
+ DEBG(">");
+ return i;
+ }
+
+
+ /* decompress until an end-of-block code */
+ if (inflate_codes(tl, td, bl, bd))
+ return 1;
+
+
+ /* free the decoding tables, return */
+ huft_free(tl);
+ huft_free(td);
+ return 0;
+}
+
+
+
+int inflate_dynamic()
+/* decompress an inflated type 2 (dynamic Huffman codes) block. */
+{
+ int i; /* temporary variables */
+ unsigned j;
+ unsigned l; /* last length */
+ unsigned m; /* mask for bit lengths table */
+ unsigned n; /* number of lengths to get */
+ struct huft *tl; /* literal/length code table */
+ struct huft *td; /* distance code table */
+ int bl; /* lookup bits for tl */
+ int bd; /* lookup bits for td */
+ unsigned nb; /* number of bit length codes */
+ unsigned nl; /* number of literal/length codes */
+ unsigned nd; /* number of distance codes */
+#ifdef PKZIP_BUG_WORKAROUND
+ unsigned ll[288+32]; /* literal/length and distance code lengths */
+#else
+ unsigned ll[286+30]; /* literal/length and distance code lengths */
+#endif
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+DEBG("<dyn");
+
+ /* make local bit buffer */
+ b = bb;
+ k = bk;
+
+
+ /* read in table lengths */
+ NEEDBITS(5)
+ nl = 257 + ((unsigned)b & 0x1f); /* number of literal/length codes */
+ DUMPBITS(5)
+ NEEDBITS(5)
+ nd = 1 + ((unsigned)b & 0x1f); /* number of distance codes */
+ DUMPBITS(5)
+ NEEDBITS(4)
+ nb = 4 + ((unsigned)b & 0xf); /* number of bit length codes */
+ DUMPBITS(4)
+#ifdef PKZIP_BUG_WORKAROUND
+ if (nl > 288 || nd > 32)
+#else
+ if (nl > 286 || nd > 30)
+#endif
+ return 1; /* bad lengths */
+
+DEBG("dyn1 ");
+
+ /* read in bit-length-code lengths */
+ for (j = 0; j < nb; j++)
+ {
+ NEEDBITS(3)
+ ll[border[j]] = (unsigned)b & 7;
+ DUMPBITS(3)
+ }
+ for (; j < 19; j++)
+ ll[border[j]] = 0;
+
+DEBG("dyn2 ");
+
+ /* build decoding table for trees--single level, 7 bit lookup */
+ bl = 7;
+ if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0)
+ {
+ if (i == 1)
+ huft_free(tl);
+ return i; /* incomplete code set */
+ }
+
+DEBG("dyn3 ");
+
+ /* read in literal and distance code lengths */
+ n = nl + nd;
+ m = mask_bits[bl];
+ i = l = 0;
+ while ((unsigned)i < n)
+ {
+ NEEDBITS((unsigned)bl)
+ j = (td = tl + ((unsigned)b & m))->b;
+ DUMPBITS(j)
+ j = td->v.n;
+ if (j < 16) /* length of code in bits (0..15) */
+ ll[i++] = l = j; /* save last length in l */
+ else if (j == 16) /* repeat last length 3 to 6 times */
+ {
+ NEEDBITS(2)
+ j = 3 + ((unsigned)b & 3);
+ DUMPBITS(2)
+ if ((unsigned)i + j > n)
+ return 1;
+ while (j--)
+ ll[i++] = l;
+ }
+ else if (j == 17) /* 3 to 10 zero length codes */
+ {
+ NEEDBITS(3)
+ j = 3 + ((unsigned)b & 7);
+ DUMPBITS(3)
+ if ((unsigned)i + j > n)
+ return 1;
+ while (j--)
+ ll[i++] = 0;
+ l = 0;
+ }
+ else /* j == 18: 11 to 138 zero length codes */
+ {
+ NEEDBITS(7)
+ j = 11 + ((unsigned)b & 0x7f);
+ DUMPBITS(7)
+ if ((unsigned)i + j > n)
+ return 1;
+ while (j--)
+ ll[i++] = 0;
+ l = 0;
+ }
+ }
+
+DEBG("dyn4 ");
+
+ /* free decoding table for trees */
+ huft_free(tl);
+
+DEBG("dyn5 ");
+
+ /* restore the global bit buffer */
+ bb = b;
+ bk = k;
+
+DEBG("dyn5a ");
+
+ /* build the decoding tables for literal/length and distance codes */
+ bl = lbits;
+ if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0)
+ {
+DEBG("dyn5b ");
+ if (i == 1) {
+ error(" incomplete literal tree\n");
+ huft_free(tl);
+ }
+ return i; /* incomplete code set */
+ }
+DEBG("dyn5c ");
+ bd = dbits;
+ if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0)
+ {
+DEBG("dyn5d ");
+ if (i == 1) {
+ error(" incomplete distance tree\n");
+#ifdef PKZIP_BUG_WORKAROUND
+ i = 0;
+ }
+#else
+ huft_free(td);
+ }
+ huft_free(tl);
+ return i; /* incomplete code set */
+#endif
+ }
+
+DEBG("dyn6 ");
+
+ /* decompress until an end-of-block code */
+ if (inflate_codes(tl, td, bl, bd))
+ return 1;
+
+DEBG("dyn7 ");
+
+ /* free the decoding tables, return */
+ huft_free(tl);
+ huft_free(td);
+
+ DEBG(">");
+ return 0;
+}
+
+
+
+int inflate_block(e)
+int *e; /* last block flag */
+/* decompress an inflated block */
+{
+ unsigned t; /* block type */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+ DEBG("<blk");
+
+ /* make local bit buffer */
+ b = bb;
+ k = bk;
+
+
+ /* read in last block bit */
+ NEEDBITS(1)
+ *e = (int)b & 1;
+ DUMPBITS(1)
+
+
+ /* read in block type */
+ NEEDBITS(2)
+ t = (unsigned)b & 3;
+ DUMPBITS(2)
+
+
+ /* restore the global bit buffer */
+ bb = b;
+ bk = k;
+
+ /* inflate that block type */
+ if (t == 2)
+ return inflate_dynamic();
+ if (t == 0)
+ return inflate_stored();
+ if (t == 1)
+ return inflate_fixed();
+
+ DEBG(">");
+
+ /* bad block type */
+ return 2;
+}
+
+
+
+int inflate()
+/* decompress an inflated entry */
+{
+ int e; /* last block flag */
+ int r; /* result code */
+ unsigned h; /* maximum struct huft's malloc'ed */
+
+
+ /* initialize window, bit buffer */
+ wp = 0;
+ bk = 0;
+ bb = 0;
+
+
+ /* decompress until the last block */
+ h = 0;
+ do {
+ hufts = 0;
+ if ((r = inflate_block(&e)) != 0)
+ return r;
+ if (hufts > h)
+ h = hufts;
+ } while (!e);
+
+ /* Undo too much lookahead. The next read will be byte aligned so we
+ * can discard unused bits in the last meaningful byte.
+ */
+ while (bk >= 8) {
+ bk -= 8;
+ inptr--;
+ }
+
+ /* flush out slide */
+ flush_output(wp);
+
+
+ /* return success */
+#ifdef DEBUG
+ fprintf(stderr, "<%u> ", h);
+#endif /* DEBUG */
+ return 0;
+}
diff --git a/arch/mips/boot/compressed/lzw.h b/arch/mips/boot/compressed/lzw.h
new file mode 100644
index 000000000..4e640f5a2
--- /dev/null
+++ b/arch/mips/boot/compressed/lzw.h
@@ -0,0 +1,42 @@
+/* lzw.h -- define the lzw functions.
+ * Copyright (C) 1992-1993 Jean-loup Gailly.
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#if !defined(OF) && defined(lint)
+# include "gzip.h"
+#endif
+
+#ifndef BITS
+# define BITS 16
+#endif
+#define INIT_BITS 9 /* Initial number of bits per code */
+
+#define LZW_MAGIC "\037\235" /* Magic header for lzw files, 1F 9D */
+
+#define BIT_MASK 0x1f /* Mask for 'number of compression bits' */
+/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free.
+ * It's a pity that old uncompress does not check bit 0x20. That makes
+ * extension of the format actually undesirable because old compress
+ * would just crash on the new format instead of giving a meaningful
+ * error message. It does check the number of bits, but it's more
+ * helpful to say "unsupported format, get a new version" than
+ * "can only handle 16 bits".
+ */
+
+#define BLOCK_MODE 0x80
+/* Block compression: if table is full and compression rate is dropping,
+ * clear the dictionary.
+ */
+
+#define LZW_RESERVED 0x60 /* reserved bits */
+
+#define CLEAR 256 /* flush the dictionary */
+#define FIRST (CLEAR+1) /* first free entry */
+
+extern int maxbits; /* max bits per code for LZW */
+extern int block_mode; /* block compress mode -C compatible with 2.0 */
+
+extern void lzw OF((int in, int out));
+extern void unlzw OF((int in, int out));
diff --git a/arch/mips/boot/compressed/misc.c b/arch/mips/boot/compressed/misc.c
new file mode 100644
index 000000000..1e3bb5f82
--- /dev/null
+++ b/arch/mips/boot/compressed/misc.c
@@ -0,0 +1,438 @@
+/*
+ * misc.c
+ *
+ * This is a collection of several routines from gzip-1.0.3
+ * adapted for Linux.
+ *
+ * Modified for Linux/MIPS 1995 by Ralf Baechle
+ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
+ * puts by Nick Holloway 1993
+ */
+
+#include "gzip.h"
+#include "lzw.h"
+
+#include <asm/segment.h>
+
+/*
+ * These are set up by the setup-routine at boot-time:
+ */
+
+struct screen_info {
+ unsigned char orig_x;
+ unsigned char orig_y;
+ unsigned char unused1[2];
+ unsigned short orig_video_page;
+ unsigned char orig_video_mode;
+ unsigned char orig_video_cols;
+ unsigned short orig_video_ega_ax;
+ unsigned short orig_video_ega_bx;
+ unsigned short orig_video_ega_cx;
+ unsigned char orig_video_lines;
+};
+
+/*
+ * This is set up by the setup-routine at boot-time
+ */
+#define EXT_MEM_K (*(unsigned short *)0x90002)
+#define DRIVE_INFO (*(struct drive_info *)0x90080)
+#define SCREEN_INFO (*(struct screen_info *)0x90000)
+#define RAMDISK_SIZE (*(unsigned short *)0x901F8)
+#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC)
+#define AUX_DEVICE_INFO (*(unsigned char *)0x901FF)
+
+#define EOF -1
+
+DECLARE(uch, inbuf, INBUFSIZ);
+DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
+DECLARE(uch, window, WSIZE);
+
+unsigned outcnt;
+unsigned insize;
+unsigned inptr;
+int graphmode;
+
+extern char input_data[];
+extern int input_len;
+
+int input_ptr;
+
+int method, exit_code, part_nb, last_member;
+int test = 0;
+int force = 0;
+int verbose = 1;
+long bytes_in, bytes_out;
+
+char *output_data;
+unsigned long output_ptr;
+
+extern int end;
+long free_mem_ptr = (long)&end;
+
+int to_stdout = 0;
+int hard_math = 0;
+
+void (*work)(int inf, int outf);
+void makecrc(void);
+
+local int get_method(int);
+
+char *vidmem = (char *)0xb8000;
+int lines, cols;
+
+static void puts(const char *);
+
+void *malloc(int size)
+{
+ void *p;
+
+ if (size <0) error("Malloc error\n");
+ if (free_mem_ptr <= 0) error("Memory error\n");
+
+ while(1) {
+ free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */
+
+ p = (void *)free_mem_ptr;
+ free_mem_ptr += size;
+
+ /*
+ * The part of the compressed kernel which has already been expanded
+ * is no longer needed. Therefore we can reuse it for malloc.
+ * With bigger kernels, this is necessary.
+ */
+
+ if (free_mem_ptr < (long)&end) {
+ if (free_mem_ptr > (long)&input_data[input_ptr])
+ error("\nOut of memory\n");
+
+ return p;
+ }
+ if (free_mem_ptr < 0x90000)
+ return p;
+ puts("large kernel, low 1M tight...");
+ free_mem_ptr = (long)input_data;
+ }
+}
+
+void free(void *where)
+{ /* Don't care */
+}
+
+static void scroll()
+{
+ int i;
+
+ memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 );
+ for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 )
+ vidmem[i] = ' ';
+}
+
+static void puts(const char *s)
+{
+ int x,y;
+ char c;
+
+ if (graphmode)
+ {
+ /*
+ * No support for graphic console. We'd need a font
+ * and that would render the compression somewhat senseless...
+ */
+ return;
+ }
+
+ x = SCREEN_INFO.orig_x;
+ y = SCREEN_INFO.orig_y;
+
+ while ( ( c = *s++ ) != '\0' ) {
+ if ( c == '\n' ) {
+ x = 0;
+ if ( ++y >= lines ) {
+ scroll();
+ y--;
+ }
+ } else {
+ vidmem [ ( x + cols * y ) * 2 ] = c;
+ if ( ++x >= cols ) {
+ x = 0;
+ if ( ++y >= lines ) {
+ scroll();
+ y--;
+ }
+ }
+ }
+ }
+
+ SCREEN_INFO.orig_x = x;
+ SCREEN_INFO.orig_y = y;
+}
+
+__ptr_t memset(__ptr_t s, int c, size_t n)
+{
+ int i;
+ char *ss = (char*)s;
+
+ for (i=0;i<n;i++) ss[i] = c;
+}
+
+__ptr_t memcpy(__ptr_t __dest, __const __ptr_t __src,
+ size_t __n)
+{
+ int i;
+ char *d = (char *)__dest, *s = (char *)__src;
+
+ for (i=0;i<__n;i++) d[i] = s[i];
+}
+
+extern ulg crc_32_tab[]; /* crc table, defined below */
+
+/* ===========================================================================
+ * Run a set of bytes through the crc shift register. If s is a NULL
+ * pointer, then initialize the crc shift register contents instead.
+ * Return the current crc in either case.
+ */
+ulg updcrc(s, n)
+ uch *s; /* pointer to bytes to pump through */
+ unsigned n; /* number of bytes in s[] */
+{
+ register ulg c; /* temporary variable */
+
+ static ulg crc = (ulg)0xffffffffL; /* shift register contents */
+
+ if (s == NULL) {
+ c = 0xffffffffL;
+ } else {
+ c = crc;
+ while (n--) {
+ c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
+ }
+ }
+ crc = c;
+ return c ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */
+}
+
+/* ===========================================================================
+ * Clear input and output buffers
+ */
+void clear_bufs()
+{
+ outcnt = 0;
+ insize = inptr = 0;
+ bytes_in = bytes_out = 0L;
+}
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty
+ * and at least one byte is really needed.
+ */
+int fill_inbuf()
+{
+ int len, i;
+
+ /* Read as much as possible */
+ insize = 0;
+ do {
+ len = INBUFSIZ-insize;
+ if (len > (input_len-input_ptr+1)) len=input_len-input_ptr+1;
+ if (len == 0 || len == EOF) break;
+
+ for (i=0;i<len;i++) inbuf[insize+i] = input_data[input_ptr+i];
+ insize += len;
+ input_ptr += len;
+ } while (insize < INBUFSIZ);
+
+ if (insize == 0) {
+ error("unable to fill buffer\n");
+ }
+ bytes_in += (ulg)insize;
+ inptr = 1;
+ return inbuf[0];
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+void flush_window()
+{
+ if (outcnt == 0) return;
+ updcrc(window, outcnt);
+
+ memcpy(&output_data[output_ptr], (char *)window, outcnt);
+
+ bytes_out += (ulg)outcnt;
+ output_ptr += (ulg)outcnt;
+ outcnt = 0;
+}
+
+/*
+ * Code to compute the CRC-32 table. Borrowed from
+ * gzip-1.0.3/makecrc.c.
+ */
+
+ulg crc_32_tab[256];
+
+void
+makecrc(void)
+{
+/* Not copyrighted 1990 Mark Adler */
+
+ unsigned long c; /* crc shift register */
+ unsigned long e; /* polynomial exclusive-or pattern */
+ int i; /* counter for all possible eight bit values */
+ int k; /* byte being shifted into crc apparatus */
+
+ /* terms of polynomial defining this crc (except x^32): */
+ static int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+ /* Make exclusive-or pattern from polynomial */
+ e = 0;
+ for (i = 0; i < sizeof(p)/sizeof(int); i++)
+ e |= 1L << (31 - p[i]);
+
+ crc_32_tab[0] = 0;
+
+ for (i = 1; i < 256; i++)
+ {
+ c = 0;
+ for (k = i | 256; k != 1; k >>= 1)
+ {
+ c = c & 1 ? (c >> 1) ^ e : c >> 1;
+ if (k & 1)
+ c ^= e;
+ }
+ crc_32_tab[i] = c;
+ }
+}
+
+void error(char *x)
+{
+ puts("\n\n");
+ puts(x);
+ puts("\n\n -- System halted");
+
+ while(1); /* Halt */
+}
+
+#define STACK_SIZE 4096UL
+
+long user_stack [STACK_SIZE];
+
+void decompress_kernel(void)
+{
+ if (boot_info.machtype == MACH_MIPS_MAGNUM_4000)
+ {
+ /*
+ * We don't have a font for graphic console so this means silence...
+ */
+ graphmode = 1;
+ }
+ else if (boot_info.machtype = MACH_ACER_PICA_61)
+ {
+ vidmem = boot_info.vram_base;
+ vidmem = vidmem + 0x8000;
+ }
+ else
+ {
+ if (SCREEN_INFO.orig_video_mode == 7)
+ vidmem = SLOTSPACE + 0xb0000;
+ else
+ vidmem = SLOTSPACE + 0xb8000;
+ }
+
+ lines = SCREEN_INFO.orig_video_lines;
+ cols = SCREEN_INFO.orig_video_cols;
+
+ if (EXT_MEM_K < 1024) error("<2M of mem\n");
+
+ output_data = (char *)0x100000; /* Points to 1M */
+ output_ptr = 0;
+
+ exit_code = 0;
+ test = 0;
+ input_ptr = 0;
+ part_nb = 0;
+
+ clear_bufs();
+ makecrc();
+
+ puts("Uncompressing Linux...");
+
+ method = get_method(0);
+
+ work(0, 0);
+
+ puts("done.\n");
+
+ puts("Now booting the kernel\n");
+}
+
+/* ========================================================================
+ * Check the magic number of the input file and update ofname if an
+ * original name was given and to_stdout is not set.
+ * Return the compression method, -1 for error, -2 for warning.
+ * Set inptr to the offset of the next byte to be processed.
+ * This function may be called repeatedly for an input file consisting
+ * of several contiguous gzip'ed members.
+ * IN assertions: there is at least one remaining compressed member.
+ * If the member is a zip file, it must be the only one.
+ */
+local int get_method(int in) /* input file descriptor */
+{
+ uch flags;
+ char magic[2]; /* magic header */
+
+ magic[0] = (char)get_byte();
+ magic[1] = (char)get_byte();
+
+ method = -1; /* unknown yet */
+ part_nb++; /* number of parts in gzip file */
+ last_member = 0;
+ /* assume multiple members in gzip file except for record oriented I/O */
+
+ if (memcmp(magic, GZIP_MAGIC, 2) == 0
+ || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
+
+ work = unzip;
+ method = (int)get_byte();
+ flags = (uch)get_byte();
+ if ((flags & ENCRYPTED) != 0)
+ error("Input is encrypted\n");
+ if ((flags & CONTINUATION) != 0)
+ error("Multi part input\n");
+ if ((flags & RESERVED) != 0) {
+ error("Input has invalid flags\n");
+ exit_code = ERROR;
+ if (force <= 1) return -1;
+ }
+ (ulg)get_byte(); /* Get timestamp */
+ ((ulg)get_byte()) << 8;
+ ((ulg)get_byte()) << 16;
+ ((ulg)get_byte()) << 24;
+
+ (void)get_byte(); /* Ignore extra flags for the moment */
+ (void)get_byte(); /* Ignore OS type for the moment */
+
+ if ((flags & EXTRA_FIELD) != 0) {
+ unsigned len = (unsigned)get_byte();
+ len |= ((unsigned)get_byte())<<8;
+ while (len--) (void)get_byte();
+ }
+
+ /* Get original file name if it was truncated */
+ if ((flags & ORIG_NAME) != 0) {
+ if (to_stdout || part_nb > 1) {
+ /* Discard the old name */
+ while (get_byte() != 0) /* null */ ;
+ } else {
+ } /* to_stdout */
+ } /* orig_name */
+
+ /* Discard file comment if any */
+ if ((flags & COMMENT) != 0) {
+ while (get_byte() != 0) /* null */ ;
+ }
+ } else
+ error("unknown compression method");
+ return method;
+}
diff --git a/arch/mips/boot/compressed/piggyback.c b/arch/mips/boot/compressed/piggyback.c
new file mode 100644
index 000000000..40284118b
--- /dev/null
+++ b/arch/mips/boot/compressed/piggyback.c
@@ -0,0 +1,81 @@
+/*
+ * linux/zBoot/piggyback.c
+ *
+ * (C) 1993 Hannu Savolainen
+ */
+
+/*
+ * This program reads the compressed system image from stdin and
+ * encapsulates it into an object file written to the stdout.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <a.out.h>
+
+int main(int argc, char *argv[])
+{
+ int c, n=0, len=0;
+ char tmp_buf[512*1024];
+
+ struct exec obj = {0x00640107}; /* object header */
+ char string_names[] = {"_input_data\0_input_len\0"};
+
+ struct nlist var_names[2] = /* Symbol table */
+ {
+ { /* _input_data */
+ (char *)4, 7, 0, 0, 0
+ },
+ { /* _input_len */
+ (char *)16, 7, 0, 0, 0
+ }
+ };
+
+
+ len = 0;
+ while ((n = read(0, &tmp_buf[len], sizeof(tmp_buf)-len+1)) > 0)
+ len += n;
+
+ if (n==-1)
+ {
+ perror("stdin");
+ exit(-1);
+ }
+
+ if (len >= sizeof(tmp_buf))
+ {
+ fprintf(stderr, "%s: Input too large\n", argv[0]);
+ exit(-1);
+ }
+
+ fprintf(stderr, "Compressed size %d.\n", len);
+
+/*
+ * Output object header
+ */
+ obj.a_data = len + sizeof(long);
+ obj.a_syms = sizeof(var_names);
+ write(1, (char *)&obj, sizeof(obj));
+
+/*
+ * Output data segment (compressed system & len)
+ */
+ write(1, tmp_buf, len);
+ write(1, (char *)&len, sizeof(len));
+
+/*
+ * Output symbol table
+ */
+ var_names[1].n_value = len;
+ write(1, (char *)&var_names, sizeof(var_names));
+
+/*
+ * Output string table
+ */
+ len = sizeof(string_names) + sizeof(len);
+ write(1, (char *)&len, sizeof(len));
+ write(1, string_names, sizeof(string_names));
+
+ exit(0);
+
+}
diff --git a/arch/mips/boot/compressed/unzip.c b/arch/mips/boot/compressed/unzip.c
new file mode 100644
index 000000000..d4a6617cd
--- /dev/null
+++ b/arch/mips/boot/compressed/unzip.c
@@ -0,0 +1,180 @@
+/* unzip.c -- decompress files in gzip or pkzip format.
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ *
+ * Adapted for Linux booting by Hannu Savolainen 1993
+ *
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ *
+ * The code in this file is derived from the file funzip.c written
+ * and put in the public domain by Mark Adler.
+ */
+
+/*
+ This version can extract files in gzip or pkzip format.
+ For the latter, only the first entry is extracted, and it has to be
+ either deflated or stored.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: unzip.c,v 0.9 1993/02/10 16:07:22 jloup Exp $";
+#endif
+
+#include "gzip.h"
+#include "crypt.h"
+
+#include <stdio.h>
+
+/* PKZIP header definitions */
+#define LOCSIG 0x04034b50L /* four-byte lead-in (lsb first) */
+#define LOCFLG 6 /* offset of bit flag */
+#define CRPFLG 1 /* bit for encrypted entry */
+#define EXTFLG 8 /* bit for extended local header */
+#define LOCHOW 8 /* offset of compression method */
+#define LOCTIM 10 /* file mod time (for decryption) */
+#define LOCCRC 14 /* offset of crc */
+#define LOCSIZ 18 /* offset of compressed size */
+#define LOCLEN 22 /* offset of uncompressed length */
+#define LOCFIL 26 /* offset of file name field length */
+#define LOCEXT 28 /* offset of extra field length */
+#define LOCHDR 30 /* size of local header, including sig */
+#define EXTHDR 16 /* size of extended local header, inc sig */
+
+
+/* Globals */
+
+int decrypt; /* flag to turn on decryption */
+char *key; /* not used--needed to link crypt.c */
+int pkzip = 0; /* set for a pkzip file */
+int extended = 0; /* set if extended local header */
+
+/* ===========================================================================
+ * Check zip file and advance inptr to the start of the compressed data.
+ * Get ofname from the local header if necessary.
+ */
+int check_zipfile(in)
+ int in; /* input file descriptors */
+{
+ uch *h = inbuf + inptr; /* first local header */
+
+ /* ifd = in; */
+
+ /* Check validity of local header, and skip name and extra fields */
+ inptr += LOCHDR + SH(h + LOCFIL) + SH(h + LOCEXT);
+
+ if (inptr > insize || LG(h) != LOCSIG) {
+ error("input not a zip");
+ }
+ method = h[LOCHOW];
+ if (method != STORED && method != DEFLATED) {
+ error("first entry not deflated or stored--can't extract");
+ }
+
+ /* If entry encrypted, decrypt and validate encryption header */
+ if ((decrypt = h[LOCFLG] & CRPFLG) != 0) {
+ error("encrypted file\n");
+ exit_code = ERROR;
+ return -1;
+ }
+
+ /* Save flags for unzip() */
+ extended = (h[LOCFLG] & EXTFLG) != 0;
+ pkzip = 1;
+
+ /* Get ofname and time stamp from local header (to be done) */
+ return 0;
+}
+
+/* ===========================================================================
+ * Unzip in to out. This routine works on both gzip and pkzip files.
+ *
+ * IN assertions: the buffer inbuf contains already the beginning of
+ * the compressed data, from offsets inptr to insize-1 included.
+ * The magic header has already been checked. The output buffer is cleared.
+ */
+void unzip(in, out)
+ int in, out; /* input and output file descriptors */
+{
+ ulg orig_crc = 0; /* original crc */
+ ulg orig_len = 0; /* original uncompressed length */
+ int n;
+ uch buf[EXTHDR]; /* extended local header */
+
+ /* ifd = in;
+ ofd = out; */
+
+ updcrc(NULL, 0); /* initialize crc */
+
+ if (pkzip && !extended) { /* crc and length at the end otherwise */
+ orig_crc = LG(inbuf + LOCCRC);
+ orig_len = LG(inbuf + LOCLEN);
+ }
+
+ /* Decompress */
+ if (method == DEFLATED) {
+
+ int res = inflate();
+
+ if (res == 3) {
+ error("out of memory");
+ } else if (res != 0) {
+ error("invalid compressed format");
+ }
+
+ } else if (pkzip && method == STORED) {
+
+ register ulg n = LG(inbuf + LOCLEN);
+
+ if (n != LG(inbuf + LOCSIZ) - (decrypt ? RAND_HEAD_LEN : 0)) {
+
+ error("length mismatch");
+ }
+ while (n--) {
+ uch c = (uch)get_byte();
+#ifdef CRYPT
+ if (decrypt) zdecode(c);
+#endif
+ if (!test) put_char(c);
+ }
+ } else {
+ error("internal error, invalid method");
+ }
+
+ /* Get the crc and original length */
+ if (!pkzip) {
+ /* crc32 (see algorithm.doc)
+ * uncompressed input size modulo 2^32
+ */
+ for (n = 0; n < 8; n++) {
+ buf[n] = (uch)get_byte(); /* may cause an error if EOF */
+ }
+ orig_crc = LG(buf);
+ orig_len = LG(buf+4);
+
+ } else if (extended) { /* If extended header, check it */
+ /* signature - 4bytes: 0x50 0x4b 0x07 0x08
+ * CRC-32 value
+ * compressed size 4-bytes
+ * uncompressed size 4-bytes
+ */
+ for (n = 0; n < EXTHDR; n++) {
+ buf[n] = (uch)get_byte(); /* may cause an error if EOF */
+ }
+ orig_crc = LG(buf+4);
+ orig_len = LG(buf+12);
+ }
+
+ /* Validate decompression */
+ if (orig_crc != updcrc(outbuf, 0)) {
+ error("crc error");
+ }
+ if (orig_len != bytes_out) {
+ error("length error");
+ }
+
+ /* Check if there are more entries in a pkzip file */
+ if (pkzip && inptr + 4 < insize && LG(inbuf+inptr) == LOCSIG) {
+ error("zip file has more than one entry");
+ }
+ extended = pkzip = 0; /* for next file */
+}
diff --git a/arch/mips/boot/compressed/xtract.c b/arch/mips/boot/compressed/xtract.c
new file mode 100644
index 000000000..91de49ca7
--- /dev/null
+++ b/arch/mips/boot/compressed/xtract.c
@@ -0,0 +1,86 @@
+/*
+ * linux/zBoot/xtract.c
+ *
+ * Copyright (C) 1993 Hannu Savolainen
+ *
+ * Extracts the system image and writes it to the stdout.
+ * based on tools/build.c by Linus Torvalds
+ */
+
+#include <stdio.h> /* fprintf */
+#include <string.h>
+#include <stdlib.h> /* contains exit */
+#include <sys/types.h> /* unistd.h needs this */
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <unistd.h> /* contains read/write */
+#include <fcntl.h>
+#include <a.out.h>
+
+#define N_MAGIC_OFFSET 1024
+
+static int GCC_HEADER = sizeof(struct exec);
+
+#define STRINGIFY(x) #x
+
+void die(char * str)
+{
+ fprintf(stderr,"%s\n",str);
+ exit(1);
+}
+
+void usage(void)
+{
+ die("Usage: xtract system [ | gzip | piggyback > piggy.s]");
+}
+
+int main(int argc, char ** argv)
+{
+ int i,c,id, sz;
+ char buf[1024];
+ char major_root, minor_root;
+ struct stat sb;
+
+ struct exec *ex = (struct exec *)buf;
+
+ if (argc != 2)
+ usage();
+
+ if ((id=open(argv[1],O_RDONLY,0))<0)
+ die("Unable to open 'system'");
+ if (read(id,buf,GCC_HEADER) != GCC_HEADER)
+ die("Unable to read header of 'system'");
+ if (N_MAGIC(*ex) == ZMAGIC) {
+ GCC_HEADER = N_MAGIC_OFFSET;
+ lseek(id, GCC_HEADER, SEEK_SET);
+ } else if (N_MAGIC(*ex) != QMAGIC)
+ die("Non-GCC header of 'system'");
+
+ sz = N_SYMOFF(*ex) - GCC_HEADER + 4; /* +4 to get the same result than tools/build */
+
+ fprintf(stderr, "System size is %d\n", sz);
+
+ while (sz)
+ {
+ int l, n;
+
+ l = sz;
+ if (l > sizeof(buf)) l = sizeof(buf);
+
+ if ((n=read(id, buf, l)) !=l)
+ {
+ if (n == -1)
+ perror(argv[1]);
+ else
+ fprintf(stderr, "Unexpected EOF\n");
+
+ die("Can't read system");
+ }
+
+ write(1, buf, l);
+ sz -= l;
+ }
+
+ close(id);
+ return(0);
+}
diff --git a/arch/mips/boot/head.S b/arch/mips/boot/head.S
deleted file mode 100644
index 73e9d2cf9..000000000
--- a/arch/mips/boot/head.S
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
- * mips/head.S
- *
- * Copyright (C) 1994 Ralf Baechle
- *
- * Head.S contains the MIPS 32-bit startup code.
- */
-
-/*
- * prevent prototypes from being imported
- */
-#define __ASSEMBLY__
-
-#include <asm/segment.h>
-#include <asm/cachectl.h>
-#include <asm/mipsregs.h>
-#include <asm/mipsconfig.h>
-#include <asm/stackframe.h>
-#include <asm/regdef.h>
-#include <linux/tasks.h>
-
-
- .globl _empty_bad_page
- .globl _empty_bad_page_table
- .globl _invalid_pg_table
- .globl _empty_zero_page
- .globl _tmp_floppy_area
- .globl _floppy_track_buffer
- .globl _swapper_pg_dir
-
- .set noreorder
-
- .text
-/*
- * This is space for the interrupt handlers.
- * They are located at virtual address 0x80000000 (physical 0x0)
- */
- /*
- * TLB refill, EXL == 0
- */
-except_vec0:
- .set noreorder
- .set noat
- /*
- * This TLB-refill handler is supposed never to cause
- * another tlb-refill exception. Unmapped pages will
- * cause another type of exception.
- */
- dmfc0 k0,CP0_CONTEXT
- dsrl k0,k0,1
- lwu k0,(k1)
- lwu k1,4(k1)
- dmtc0 k0,CP0_ENTRYLO0
- dmtc0 k0,CP0_ENTRYLO1
- tlbwr
- eret
-
- /*
- * XTLB refill, EXL == 0 (X == 64-bit TLB)
- */
- .org except_vec0+0x80
-except_vec1:
- /*
- * Not used yet...
- */
- eret
-
- /*
- * Cache Error
- */
- .org except_vec1+0x80
-except_vec2:
- /*
- * Not used yet...
- */
- eret
-
- /*
- * General exception vector.
- */
- .org except_vec2+0x80
-except_vec3:
- SAVE_ALL
- mfc0 t0,CP0_STATUS
- ori t0,t0,0x1f
- xori t0,t0,0x1f
- mtc0 t0,CP0_STATUS
- .set at
- la k0,_exception_handlers
- mfc0 k1,CP0_CAUSE
- andi k1,k1,0x7c
- addu k0,k0,k1
- lw k0,(k0)
- FILL_LDS
- jr k0
- nop
-
-
-/******************************************************************************/
-
- /*
- * The following data is expected to be at certain absolute
- * addresses, which are hardwired in
- * include/asm-mips/mipsconfig.h
- * If the following offset is to short, the assembler will
- * break with an assertion failure. You then will have to
- * increase it and to fix the address in
- * include/asm-mips/mipsconfig.h
- */
-
- .org except_vec3+0x100
- .globl _kernelsp
-_kernelsp: .word 0
-
-kernel_entry:
-
-/*
- * Flush the TLB
- */
- dmtc0 zero,CP0_ENTRYHI
- dmtc0 zero,CP0_ENTRYLO0
- dmtc0 zero,CP0_ENTRYLO1
- li t0,NUMBER_OF_TLB_ENTRIES-1
-1: mtc0 t0,CP0_INDEX
- tlbwi
- bne zero,t0,1b
- subu t0,t0,1
-
-/*
- * Initialize memory management.
- * Wire mapping for port i/o space 0xe0000000 -> 0x9000000900000000
- */
- li t0,3
- mtc0 t0,CP0_WIRED
- li t0,PM_64K
- mtc0 t0,CP0_PAGEMASK
- la t3,map0
- ld t1,0(t3)
- ld t2,8(t3)
- mtc0 zero,CP0_INDEX
- dmtc0 t1,CP0_ENTRYHI
- dmtc0 t2,CP0_ENTRYLO0
- dmtc0 zero,CP0_ENTRYLO1 /* Invalid page */
- tlbwi
- li t0,PM_1M
- mtc0 t0,CP0_PAGEMASK
- ld t1,16(t3)
- ld t2,24(t3)
- li t0,1
- mtc0 t0,CP0_INDEX
- dmtc0 t1,CP0_ENTRYHI
- dmtc0 t2,CP0_ENTRYLO0
- tlbwi
- ld t1,32(t3)
- ld t2,40(t3)
- li t0,2
- mtc0 t0,CP0_INDEX
- dmtc0 t1,CP0_ENTRYHI
- dmtc0 t2,CP0_ENTRYLO0
- tlbwi
-
-/*
- * We always use 4k pages. Therefore the PageMask register
- * is expected to be setup for 4k pages.
- */
- li t0,PM_4K
- mtc0 t0,CP0_PAGEMASK
-
-/*
- * Clear BSS first so that there are no surprises...
- */
- la t0,__edata
- la t1,__end
- sw zero,(t0)
-1: addiu t0,t0,4
- bnel t0,t1,1b
- sw zero,(t0)
-
-/*
- * Copy bootup parameters out of the way. First 2kB of
- * _empty_zero_page is for boot parameters, second 2kB
- * is for the command line.
- */
-#if 0
- movl $0x90000,%esi
- movl $_empty_zero_page,%edi
- movl $512,%ecx
- cld
- rep
- movsl
- xorl %eax,%eax
- movl $512,%ecx
- rep
- stosl
- cmpw $(CL_MAGIC),CL_MAGIC_ADDR
- jne 1f
- movl $_empty_zero_page+2048,%edi
- movzwl CL_OFFSET,%esi
- addl $(CL_BASE_ADDR),%esi
- movl $2048,%ecx
- rep
- movsb
-#endif
-
- /*
- * Preliminary stack...
- */
- la sp,0x80700000
- sw sp,_kernelsp
-6:
- jal _start_kernel
- nop
- j 6b # main should never return here, but
- # just in case, we know what happens.
-
-#if 0
-/* This is the default interrupt "handler" :-) */
-int_msg:
- .asciz "Unknown interrupt\n"
-.align 2
-ignore_int:
- cld
- pushl %eax
- pushl %ecx
- pushl %edx
- push %ds
- push %es
- push %fs
- movl $(KERNEL_DS),%eax
- mov %ax,%ds
- mov %ax,%es
- mov %ax,%fs
- pushl $int_msg
- call _printk
- popl %eax
- pop %fs
- pop %es
- pop %ds
- popl %edx
- popl %ecx
- popl %eax
- iret
-#endif
-
-#define CACHELINES 512 /* number of cachelines */
-
-/*
- * Flush instruction/data caches
- *
- * Parameters: a0 - starting address to flush
- * a1 - size of area to be flushed
- * a2 - which caches to be flushed
- *
- * FIXME: - ignores parameters
- * - doesn't know about second level caches
- */
-
- .set noreorder
- .globl _cacheflush
- .text
-_cacheflush:
- /*
- * Flush the instruction cache
- */
- lui t0,0x8000
- li t1,CACHELINES-1
-1: cache 0,0(t0)
- cache 0,32(t0)
- cache 0,64(t0)
- cache 0,96(t0)
- cache 0,128(t0)
- cache 0,160(t0)
- cache 0,192(t0)
- cache 0,224(t0)
- cache 0,256(t0)
- cache 0,288(t0)
- cache 0,320(t0)
- cache 0,352(t0)
- cache 0,384(t0)
- cache 0,416(t0)
- cache 0,448(t0)
- cache 0,480(t0)
- addiu t0,t0,512
- bne zero,t1,1b
- subu t1,t1,1
- /*
- * Flush the data cache
- */
- lui t0,0x8000
- li t1,CACHELINES-1
-1: cache 1,0(t0)
- cache 1,32(t0)
- cache 1,64(t0)
- cache 1,96(t0)
- cache 1,128(t0)
- cache 1,160(t0)
- cache 1,192(t0)
- cache 1,224(t0)
- cache 1,256(t0)
- cache 1,288(t0)
- cache 1,320(t0)
- cache 1,352(t0)
- cache 1,384(t0)
- cache 1,416(t0)
- cache 1,448(t0)
- cache 1,480(t0)
- addiu t0,t0,512
- bne zero,t1,1b
- subu t1,t1,1
-
- j ra
- nop
-
- .globl _beep
-_beep: lbu t0,0xe0000061
- xori t0,t0,3
- sb t0,0xe0000061
- jr ra
- nop
-
-/*
- * Instead of Intel's strage and unportable segment descriptor magic
- * we difference user and kernel space by their address.
- * Kernel space (== physical memory) is mapped at 0x80000000,
- * User space is mapped at 0x0.
- */
-
- .data
-
- .globl _segment_fs
- /*
- * Inital wired mappings
- */
-map0: .quad 0xc00000ffe0000000,0x24000017
- .quad 0xc00000ffe1000000,0x04000017
- .quad 0xc00000ffe2000000,0x04020017
-
-/*
- * page 0 is made non-existent, so that kernel NULL pointer references get
- * caught. Thus the swapper page directory has been moved to 0x1000
- *
- * XXX Actually, the swapper page directory is at 0x1000 plus 1 megabyte,
- * with the introduction of the compressed boot code. Theoretically,
- * the original design of overlaying the startup code with the swapper
- * page directory is still possible --- it would reduce the size of the kernel
- * by 2-3k. This would be a good thing to do at some point.....
- */
- .text
-
- .org 0x1000
-_swapper_pg_dir:
-/*
- * The page tables are initialized to only 4MB here - the final page
- * tables are set up later depending on memory size.
- */
- .org 0x2000
-_pg0:
-
- .org 0x3000
-_empty_bad_page:
-
- .org 0x4000
-_empty_bad_page_table:
-
- .org 0x5000
-_invalid_pg_table:
-
- .org 0x6000
-_empty_zero_page:
-
- .org 0x7000
-
-/*
- * tmp_floppy_area is used by the floppy-driver when DMA cannot
- * reach to a buffer-block. It needs to be aligned, so that it isn't
- * on a 64kB border.
- */
-_tmp_floppy_area: .fill 1024,1,0
-/*
- * floppy_track_buffer is used to buffer one track of floppy data: it
- * has to be separate from the tmp_floppy area, as otherwise a single-
- * sector read/write can mess it up. It can contain one full cylinder (sic) of
- * data (36*2*512 bytes).
- */
-_floppy_track_buffer: .fill 512*2*36,1,0
-
-_segment_fs: .word KERNEL_DS
diff --git a/arch/mips/boot/loader.h b/arch/mips/boot/loader.h
new file mode 100644
index 000000000..610111b9a
--- /dev/null
+++ b/arch/mips/boot/loader.h
@@ -0,0 +1,24 @@
+/*
+ * Defines for Linux/MIPS executable loaders
+ *
+ * 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 by Ralf Baechle
+ */
+#ifndef __STAND_LOADER
+#define __STAND_LOADER
+
+struct loader {
+ struct nlist *(*ld_get_nlist)(char *symbol);
+ char *(*ld_isymbol)(char *);
+ u_long (*ld_get_kbase)(void);
+ u_long (*ld_get_ksize)(void);
+ int (*ld_load_kernel)(void *mem);
+ void (*ld_print_stats)(void);
+ int (*ld_open_kernel)(char *kernel);
+ void (*ld_close_kernel)(void);
+};
+
+#endif /* __STAND_LOADER */
diff --git a/arch/mips/boot/milo.c b/arch/mips/boot/milo.c
new file mode 100644
index 000000000..a8a25dd91
--- /dev/null
+++ b/arch/mips/boot/milo.c
@@ -0,0 +1,316 @@
+/*
+ * Load and launch Linux/MIPS kernel.
+ *
+ * Copyright (C) 1994, 1995 by Waldorf Electronics,
+ * written by Ralf Baechle and Andreas Busse
+ *
+ * Loosly based on bootstrap.c for Linux/68k,
+ * Copyright (C) 1993 by Hamish Macdonald, Greg Harp
+ *
+ * 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.
+ */
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sys/file.h>
+#include <sys/types.h>
+
+#include <linux/string.h>
+#include <linux/tty.h>
+#include <linux/a.out.h>
+
+/*
+ * Prototypes
+ */
+void usage(void);
+
+/*
+ * Defaults, may be overiden by option or environment.
+ */
+static char *kernel_name = KERNEL_NAME;
+static char *ramdisk_name = NULL;
+int option_debuglevel = 0;
+int option_verbose = 1;
+int behaviour = BEHAVE_MILO;
+
+extern char *optarg;
+
+extern volatile void launch(char *kptr, char *rdptr,
+ u_long kernel_size, u_long rd_size);
+
+static char *kptr; /* kernel will be loaded there */
+static char *rdptr; /* ramdisk will be loaded there */
+
+u_long loadaddr = LOADADDR; /* mallocinit() needs that */
+u_long kernel_base = KERNELBASE; /* whereever that is... */
+u_long start_mem; /* always true on an ARC system */
+u_long mem_size;
+u_long rd_size;
+u_long kernel_entry;
+u_long kernel_size;
+u_long kernel_bss_end;
+
+struct bootinfo bi; /* Linux boot info */
+struct screen_info si; /* Linux screen info */
+struct DisplayInfo *di; /* ARC display info */
+
+
+/*
+ * For now we just use the aout loader
+ */
+extern struct loader loader_aout;
+struct loader *kld = &loader_aout;
+
+/*
+ * main()
+ */
+int main(int argc, char *argv[])
+{
+ int ch;
+
+ /*
+ * Print the greet message
+ */
+ printf("Linux/MIPS ARC Standalone Shell ");
+ printf("V" STR(VERSION) "\r\n");
+ printf("Copyright (C) Waldorf Electronics and others 1994, 1995\r\n\r\n");
+
+ /*
+ * Analyse arguments
+ */
+ if(argc > 1)
+ {
+ while ((ch = getopt(argc, argv, "dik:r:v")) != EOF)
+ switch (ch)
+ {
+ case 'd':
+ option_debuglevel++;
+ option_verbose = 1;
+ break;
+ case 'i':
+ interactive = 1;
+ break;
+ case 'k':
+ kernel_name = optarg;
+ break;
+ case 'r':
+ ramdisk_name = optarg;
+ break;
+ case 'v':
+ option_verbose = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ }
+}
+
+/*
+ * Do the actual boot
+ */
+int do_boot(char *kernel_name, char *ramdisk_name)
+{
+ int kfd, rfd = -1, i;
+ u_long memreq;
+ struct nlist *nl;
+ u_long kbi_offset, ksi_offset;
+
+ /*
+ * Verify that there is enough RAM
+ */
+ mem_size = bi.memupper - bi.memlower;
+ if (mem_size < 0x800000)
+ {
+ fprintf(stderr,
+ "Insufficient Memory to load Linux/MIPS, aborting\n\r");
+ return(5);
+ }
+
+ if (behaviour == BEHAVE_ARCDB)
+ {
+ printf("%s: kernel file is `%s'\r\n", NAMEOF_ARCDB, kernel_name);
+ if (ramdisk_name)
+ printf("%s: ramdisk file is `%s'\r\n", NAMEOF_ARCDB, ramdisk_name);
+ }
+
+ /*
+ * Open kernel and gather some data from the executable
+ */
+ if (kld->ld_open_kernel(kernel_name) < 0)
+ {
+ fprintf(stderr, "Error opening kernel file %s.\n\r", kernel_name);
+ return 5;
+ }
+ kernel_base = kld->ld_get_kbase();
+ kernel_size = kld->ld_get_ksize();
+
+ bi.ramdisk_size = 0; /* default: no ramdisk */
+ if (ramdisk_name)
+ {
+ if ((rfd = open (ramdisk_name, O_RDONLY)) == -1)
+ {
+ fprintf (stderr,
+ "Unable to open ramdisk file %s\n\r", ramdisk_name);
+ }
+ else
+ {
+ /*
+ * record ramdisk size
+ */
+ bi.ramdisk_size = (lseek (rfd, 0, L_XTND) + 1023) >> 10;
+
+ rd_size = lseek (rfd, 0, L_XTND);
+ if (rd_size & ((1<<10)-1))
+ {
+ /*
+ * Most probably the file is no image at all or has been
+ * corrupted, so print a warning message.
+ */
+ printf("Warning: Ramdisk size is not multiple of 1024 bytes.\r\n");
+ }
+ bi.ramdisk_size = rd_size >> 10;
+ }
+ }
+ bi.ramdisk_base = (u_long)start_mem + mem_size - rd_size;
+
+ /*
+ * find offset to boot_info structure
+ */
+ if (!(nl = kld->ld_get_nlist (kld->ld_isymbol("boot_info"))))
+ {
+ perror("get_nlist1");
+ return 1;
+ }
+ else
+ {
+ kbi_offset = nl->n_value - kernel_base;
+ free(nl);
+ }
+
+ /*
+ * Find offset to screen_info structure
+ */
+ if (!(nl = kld->ld_get_nlist (kld->ld_isymbol("screen_info"))))
+ {
+ perror("get_nlist2");
+ return 1;
+ }
+ else
+ {
+ ksi_offset = nl->n_value - kernel_base;
+ free(nl);
+ }
+
+ /*
+ * Find kernel entry point
+ */
+ if (!(nl = kld->ld_get_nlist (kld->ld_isymbol("kernel_entry"))))
+ {
+ perror("get_nlist3");
+ return 1;
+ }
+ else
+ {
+ kernel_entry = nl->n_value;
+ free(nl);
+ }
+
+ /*
+ * End of bss segment - ramdisk will be placed there
+ */
+ if (!(nl = kld->ld_get_nlist (kld->ld_isymbol("_end"))))
+ {
+ perror("get_nlist3");
+ return 1;
+ }
+ else
+ {
+ kernel_bss_end = nl->n_value;
+ free(nl);
+ }
+
+ /*
+ * allocate buffers for kernel and ramdisk
+ */
+ if (!(kptr = (char *) malloc(kernel_size)))
+ {
+ fprintf (stderr, "Unable to allocate %d bytes of memory\n\r", memreq);
+ return 1;
+ }
+ memset (kptr, 0, kernel_size);
+
+ if (rd_size)
+ {
+ if (!(rdptr = (char *) malloc(rd_size)))
+ {
+ fprintf (stderr,
+ "Unable to allocate %d bytes of memory\n\r", memreq);
+ return 1;
+ }
+ memset (rdptr, 0, rd_size);
+ }
+
+ /*
+ * Should check whether kernel & RAMdisk moving doesn't overwrite
+ * the bootstraper during startup.
+ */
+ if (option_verbose)
+ {
+ /*
+ * The following text should be printed by the loader module
+ */
+ printf ("\r\n");
+ kld->ld_print_stats();
+ printf ("Kernel entry at 0x%08lx\n\r", kernel_entry);
+ }
+
+ /*
+ * Now do the real loading
+ */
+ if (kld->ld_load_kernel(kptr) < 0)
+ {
+ fprintf (stderr, "Failed to load kernel executable\r\n");
+ free(kptr);
+ exit (EXIT_FAILURE);
+ }
+ kld->ld_close_kernel();
+
+ /*
+ * copy the boot and screen info structures to the kernel image,
+ * then execute the copy-and-go code
+ */
+ memcpy ((void *)(kptr + kbi_offset), &bi, sizeof(bi));
+ memcpy ((void *)(kptr + ksi_offset), &si, sizeof(si));
+
+ /*
+ * Write the manipulated kernel back
+ */
+
+ /*
+ * Success...
+ */
+ return 0;
+}
+
+/*
+ * usage()
+ *
+ * Options:
+ * -d - enable debugging (default is no debugging)
+ * -i - interactive (default is noninteractive)
+ * -k - kernel executable (default multi(0)disk(0)fdisk(0)\VMLINUX)
+ * -r - ramdisk image (default is no ramdisk)
+ * -v - verbose output
+ */
+void usage(void)
+{
+ fprintf (stderr, "Usage:\r\n"
+ "\tmilo [-d] [-i] [-k kernel_executable] [-r ramdisk_file] [-v]"
+ " [option...]\r\n");
+ exit (EXIT_FAILURE);
+}
diff --git a/arch/mips/config.in b/arch/mips/config.in
index 24f0c13f9..6ecc5e698 100644
--- a/arch/mips/config.in
+++ b/arch/mips/config.in
@@ -3,28 +3,84 @@
# see the Configure script.
#
+comment 'Machine setup'
+
+bool 'Support for Acer PICA 1 chipset' CONFIG_ACER_PICA_61 y
+bool 'Support for DECstation' CONFIG_DECSTATION n
+bool 'Support for Deskstation RPC44' CONFIG_DESKSTATION_RPC44 n
+bool 'Support for Deskstation Tyne' CONFIG_DESKSTATION_TYNE n
+bool 'Support for Mips Magnum 3000' CONFIG_MIPS_MAGNUM_3000 n
+bool 'Support for Mips Magnum 4000' CONFIG_MIPS_MAGNUM_4000 y
+if [ "$CONFIG_ACER_PICA_61" = "y" -o \
+ "$CONFIG_MIPS_MAGNUM_4000" = "y" -o \
+ "$CONFIG_OLIVETTI_M700" = "y" ]; then
+ echo "#define CONFIG_MIPS_JAZZ" >> $CONFIG_H
+ echo "CONFIG_MIPS_JAZZ=y" >> $CONFIG
+ CONFIG_MIPS_JAZZ=y
+fi
+
+comment 'CPU selection'
+
+bool 'Generate code for R3000' CONFIG_CPU_R3000 n
+#bool 'Generate code for R6000' CONFIG_CPU_R6000 n
+bool 'Generate code for R4x00' CONFIG_CPU_R4X00 y
+bool 'Generate code for R4600' CONFIG_CPU_R4600 n
+bool 'Generate code for R8000' CONFIG_CPU_R8000 n
+bool 'Generate code for R10000' CONFIG_CPU_R10000 n
+bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN y
+bool 'Compile the kernel into the ELF object format' CONFIG_MIPS_ELF n
+if [ "$CONFIG_MIPS_ELF" = "y" ]; then
+ bool 'Is your normal Linux/MIPS compiler the ELF compiler' CONFIG_ELF_COMPILER n
+fi
+
comment 'General setup'
-bool 'Normal floppy disk support' CONFIG_BLK_DEV_FD n
-bool 'Normal harddisk support' CONFIG_BLK_DEV_HD n
+bool 'Normal floppy disk support' CONFIG_BLK_DEV_FD y
+bool 'Normal (MFM/RLL) disk and IDE disk/cdrom support' CONFIG_ST506 n
+if [ "$CONFIG_ST506" = "y" ]; then
+ comment 'Please see block/drivers/README.ide for help/info on IDE drives'
+ bool ' Use old (reliable) disk-only driver for primary i/f' CONFIG_BLK_DEV_HD y
+ if [ "$CONFIG_BLK_DEV_HD" = "y" ]; then
+ bool ' Include new IDE driver for secondary i/f support' CONFIG_BLK_DEV_IDE n
+ else
+ bool ' Use new IDE driver for primary/secondary i/f' CONFIG_BLK_DEV_IDE n
+ fi
+ if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then
+ bool ' Include support for IDE CDROM (ATAPI)' CONFIG_BLK_DEV_IDECD n
+ fi
+fi
+
bool 'XT harddisk support' CONFIG_BLK_DEV_XD n
-bool 'Networking support' CONFIG_NET n
+bool 'Networking support' CONFIG_NET y
bool 'System V IPC' CONFIG_SYSVIPC n
bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF n
if [ "$CONFIG_NET" = "y" ]; then
comment 'Networking options'
-bool 'TCP/IP networking' CONFIG_INET n
-if [ "$CONFIG_INET" "=" "y" ]; then
-bool 'IP forwarding/gatewaying' CONFIG_IP_FORWARD y
+bool 'TCP/IP networking' CONFIG_INET y
+if [ "$CONFIG_INET" = "y" ]; then
+bool 'IP: forwarding/gatewaying' CONFIG_IP_FORWARD n
+bool 'IP: multicasting' CONFIG_IP_MULTICAST n
+bool 'IP: firewalling' CONFIG_IP_FIREWALL n
+bool 'IP: accounting' CONFIG_IP_ACCT n
+bool 'IP: tunneling' CONFIG_NET_IPIP n
+if [ "$CONFIG_IP_FORWARD" = "y" -a "$CONFIG_IP_FIREWALL" = "y" ]; then
+ bool 'IP: firewall packet logging' CONFIG_IP_FIREWALL_VERBOSE y
+ bool 'IP: masquerading (ALPHA)' CONFIG_IP_MASQUERADE n
+fi
comment '(it is safe to leave these untouched)'
-bool 'PC/TCP compatibility mode' CONFIG_INET_PCTCP n
-bool 'Reverse ARP' CONFIG_INET_RARP n
-bool 'Assume subnets are local' CONFIG_INET_SNARL y
-bool 'Disable NAGLE algorithm (normally enabled)' CONFIG_TCP_NAGLE_OFF n
+bool 'IP: PC/TCP compatibility mode' CONFIG_INET_PCTCP n
+bool 'IP: Reverse ARP' CONFIG_INET_RARP n
+bool 'IP: Assume subnets are local' CONFIG_INET_SNARL y
+bool 'IP: Disable NAGLE algorithm (normally enabled)' CONFIG_TCP_NAGLE_OFF n
+bool 'IP: Drop source routed frames' CONFIG_IP_NOSR y
fi
bool 'The IPX protocol' CONFIG_IPX n
-#bool 'Amateur Radio AX.25 Level 2' CONFIG_AX25 n
+bool 'Appletalk DDP' CONFIG_ATALK n
+bool 'Amateur Radio AX.25 Level 2' CONFIG_AX25 n
+if [ "$CONFIG_AX25" = "y" ]; then
+ bool 'Amateur Radio NET/ROM' CONFIG_NETROM n
+fi
fi
comment 'SCSI support'
@@ -39,20 +95,28 @@ else
comment 'SCSI support type (disk, tape, CDrom)'
-bool 'Scsi disk support' CONFIG_BLK_DEV_SD y
-bool 'Scsi tape support' CONFIG_CHR_DEV_ST y
-bool 'Scsi CDROM support' CONFIG_BLK_DEV_SR y
-bool 'Scsi generic support' CONFIG_CHR_DEV_SG y
+bool 'SCSI disk support' CONFIG_BLK_DEV_SD y
+bool 'SCSI tape support' CONFIG_CHR_DEV_ST y
+bool 'SCSI CDROM support' CONFIG_BLK_DEV_SR y
+bool 'SCSI generic support' CONFIG_CHR_DEV_SG n
+
+comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
+
+bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN n
comment 'SCSI low-level drivers'
-bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X n
-bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 y
-bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 n
+bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X y
+bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 n
+bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 y
bool 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC n
+bool 'EATA-DMA (DPT,NEC&ATT for ISA,EISA,PCI) support' CONFIG_SCSI_EATA_DMA n
+bool 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F n
bool 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN n
bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 n
-bool 'NCR53c7,8xx SCSI support' CONFIG_SCSI_NCR53C7xx n
+if [ "$CONFIG_PCI" = "y" ]; then
+ bool 'NCR53c7,8xx SCSI support' CONFIG_SCSI_NCR53C7xx n
+fi
bool 'Always IN2000 SCSI support (test release)' CONFIG_SCSI_IN2000 n
bool 'PAS16 SCSI support' CONFIG_SCSI_PAS16 n
bool 'QLOGIC SCSI support' CONFIG_SCSI_QLOGIC n
@@ -60,7 +124,7 @@ bool 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE
bool 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 n
bool 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR n
bool '7000FASST SCSI support' CONFIG_SCSI_7000FASST n
-bool 'EISA EATA support' CONFIG_SCSI_EATA n
+#bool 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA n
#bool 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG n
fi
@@ -75,22 +139,30 @@ if [ "$CONFIG_NETDEVICES" = "n" ]; then
comment 'Skipping network driver configuration options...'
else
-bool 'Dummy net driver support' CONFIG_DUMMY n
+bool 'Dummy net driver support' CONFIG_DUMMY y
bool 'SLIP (serial line) support' CONFIG_SLIP n
if [ "$CONFIG_SLIP" = "y" ]; then
- bool ' CSLIP compressed headers' SL_COMPRESSED y
-# bool ' SLIP debugging on' SL_DUMP y
+ bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED y
+ bool ' 16 channels instead of 4' SL_SLIP_LOTS n
fi
bool 'PPP (point-to-point) support' CONFIG_PPP n
+if [ "$CONFIG_PPP" = "y" ]; then
+ bool ' 16 channels instead of 4' CONFIG_PPP_LOTS n
+fi
+if [ "$CONFIG_AX25" = "y" ]; then
+ bool 'Z8530 SCC kiss emulation driver for AX.25' CONFIG_SCC y
+fi
bool 'PLIP (parallel port) support' CONFIG_PLIP n
+bool 'EQL (serial line load balancing) support' CONFIG_EQUALIZER n
bool 'Load balancing support (experimental)' CONFIG_SLAVE_BALANCING n
bool 'Do you want to be offered ALPHA test drivers' CONFIG_NET_ALPHA n
-bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC y
+bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC n
if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
- bool 'WD80*3 support' CONFIG_WD80x3 y
+ bool 'WD80*3 support' CONFIG_WD80x3 n
bool 'SMC Ultra support' CONFIG_ULTRA n
fi
-bool '3COM cards' CONFIG_NET_VENDOR_3COM y
+bool 'AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE n
+bool '3COM cards' CONFIG_NET_VENDOR_3COM n
if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
bool '3c501 support' CONFIG_EL1 n
bool '3c503 support' CONFIG_EL2 n
@@ -102,32 +174,54 @@ if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
fi
bool 'Other ISA cards' CONFIG_NET_ISA n
if [ "$CONFIG_NET_ISA" = "y" ]; then
- bool 'AT1500 and NE2100 (LANCE and PCnet-ISA) support' CONFIG_LANCE n
- bool 'Cabletron E21xx support (not recommended)' CONFIG_E2100 n
+ bool 'Arcnet support' CONFIG_ARCNET n
+ bool 'Cabletron E21xx support' CONFIG_E2100 n
bool 'DEPCA support' CONFIG_DEPCA n
bool 'EtherWorks 3 support' CONFIG_EWRK3 n
if [ "$CONFIG_NET_ALPHA" = "y" ]; then
- bool 'EtherExpress support' CONFIG_EEXPRESS n
bool 'AT1700 support' CONFIG_AT1700 n
+# bool 'EtherExpressPro support' CONFIG_EEXPRESS_PRO n
+ bool 'EtherExpress support' CONFIG_EEXPRESS n
+ bool 'NI5210 support' CONFIG_NI52 n
+ bool 'NI6510 support' CONFIG_NI65 n
+ bool 'WaveLAN support' CONFIG_WAVELAN n
fi
- bool 'HP PCLAN support' CONFIG_HPLAN n
- bool 'HP PCLAN PLUS support' CONFIG_HPLAN_PLUS n
+ bool 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS n
+ bool 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN n
bool 'NE2000/NE1000 support' CONFIG_NE2000 y
+ if [ "$CONFIG_AX25" = "y" ]; then
+ bool 'Ottawa PI and PI/2 support' CONFIG_PI y
+ fi
bool 'SK_G16 support' CONFIG_SK_G16 n
fi
-bool 'EISA and on board controllers' CONFIG_NET_EISA n
+bool 'EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA n
+if [ "$CONFIG_NET_EISA" = "y" ]; then
if [ "$CONFIG_NET_ALPHA" = "y" ]; then
bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n
fi
bool 'Apricot Xen-II on board ethernet' CONFIG_APRICOT n
-#bool 'NI52EE support' CONFIG_NI52 n
-#bool 'NI65EE support' CONFIG_NI65 n
+# bool 'DEC 21040 PCI support' CONFIG_DEC_ELCP n
+# bool 'LPL T100V 100Mbs support' CONFIG_LPL_T100 n
+# bool 'PCnet32 (32 bit VLB and PCI LANCE) support' CONFIG_PCNET32 n
+# bool 'Zenith Z-Note support' CONFIG_ZNET n
+fi
+
+if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then
+ bool 'MIPS JAZZ onboard SONIC ethernet support' CONFIG_MIPS_JAZZ_SONIC y
+fi
+
bool 'Pocket and portable adaptors' CONFIG_NET_POCKET n
if [ "$CONFIG_NET_POCKET" = "y" ]; then
+ bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n
bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n
bool 'D-Link DE620 pocket adaptor support' CONFIG_DE620 n
- bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n
- bool 'Zenith Z-Note support' CONFIG_ZNET n
+# bool 'Silicom pocket adaptor support' CONFIG_SILICOM_PEA n
+# bool 'WaveLAN PCMCIA support' CONFIG_WaveLAN n
+# bool '3 Com 3c589 PCMCIA support' CONFIG_3C589 n
+fi
+bool 'Token Ring driver support' CONFIG_TR n
+if [ "$CONFIG_TR" = "y" ]; then
+ bool 'IBM Tropic chipset based adaptor support' CONFIG_IBMTR y
fi
fi
fi
@@ -149,17 +243,18 @@ fi
comment 'Filesystems'
-bool 'Standard (minix) fs support' CONFIG_MINIX_FS y
+bool 'Standard (minix) fs support' CONFIG_MINIX_FS n
bool 'Extended fs support' CONFIG_EXT_FS n
-bool 'Second extended fs support' CONFIG_EXT2_FS n
+bool 'Second extended fs support' CONFIG_EXT2_FS y
bool 'xiafs filesystem support' CONFIG_XIA_FS n
bool 'msdos fs support' CONFIG_MSDOS_FS n
if [ "$CONFIG_MSDOS_FS" = "y" ]; then
-bool 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS n
+#bool 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS n
+comment 'Umsdos is not supported in 1.3.0: wait for 1.3.1'
fi
bool '/proc filesystem support' CONFIG_PROC_FS n
if [ "$CONFIG_INET" = "y" ]; then
-bool 'NFS filesystem support' CONFIG_NFS_FS y
+bool 'NFS filesystem support' CONFIG_NFS_FS n
fi
if [ "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_CDU31A" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_BLK_DEV_IDECD" = "y" ]; then
bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS y
@@ -171,7 +266,9 @@ bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS n
comment 'character devices'
-bool 'Parallel printer support' CONFIG_PRINTER n
+bool 'Parallel printer support' CONFIG_PRINTER y
+bool 'Standard serial device support' CONFIG_SERIAL y
+bool 'Cyclades async mux support' CONFIG_CYCLADES n
bool 'Logitech busmouse support' CONFIG_BUSMOUSE n
bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE n
if [ "$CONFIG_PSMOUSE" = "y" ]; then
@@ -179,8 +276,7 @@ bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE n
fi
bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n
bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n
-bool 'Selection (cut and paste for virtual consoles)' CONFIG_SELECTION n
-
+
bool 'QIC-02 tape support' CONFIG_QIC02_TAPE n
if [ "$CONFIG_QIC02_TAPE" = "y" ]; then
bool 'Do you want runtime configuration for QIC-02' CONFIG_QIC02_DYNCONF n
@@ -207,8 +303,12 @@ bool 'Sound card support' CONFIG_SOUND n
comment 'Kernel hacking'
+bool 'Remote kernel debugging support' CONFIG_REMOTE_DEBUG n
#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC n
bool 'Kernel profiling support' CONFIG_PROFILE n
+if [ "$CONFIG_PROFILE" = "y" ]; then
+ int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
+fi
if [ "$CONFIG_SCSI" = "y" ]; then
-bool 'Verbose scsi error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS y
+bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS y
fi
diff --git a/arch/mips/dummy.c b/arch/mips/dummy.c
deleted file mode 100644
index b85a1d71e..000000000
--- a/arch/mips/dummy.c
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * This file handles Systemcalls not available for all CPUs.
- *
- * Written by Ralf Baechle,
- * Copyright (C) 1994 by Waldorf GMBH
- */
-
-unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
-{
- printk("clone_page_tables\n");
- return start_mem;
-}
-
-void fake_keyboard_interrupt(void)
-{
-/* printk("fake_keyboard_interrupt\n"); */
-}
diff --git a/arch/mips/entry.S b/arch/mips/entry.S
deleted file mode 100644
index ebf2c1d9c..000000000
--- a/arch/mips/entry.S
+++ /dev/null
@@ -1,665 +0,0 @@
-/*
- * linux/kernel/mips/sys_call.S
- *
- * Copyright (C) 1994 Waldorf GMBH
- * written by Ralf Baechle
- */
-
-/*
- * sys_call.S contains the system-call and fault low-level handling routines.
- * This also contains the timer-interrupt handler, as well as all interrupts
- * and faults that can result in a task-switch.
- */
-
-#define __ASSEMBLY__
-
-#include <linux/sys.h>
-#include <asm/segment.h>
-#include <asm/mipsregs.h>
-#include <asm/mipsconfig.h>
-#include <asm/stackframe.h>
-#include <asm/regdef.h>
-
-/*
- * These are offsets into the task-struct.
- */
-state = 0
-counter = 4
-priority = 8
-signal = 12
-blocked = 16
-flags = 20
-errno = 24 #/* MIPS OK */
-exec_domain = 60 #/* ??? */
-
-ENOSYS = 38
-
- .globl _system_call
- .globl _lcall7
- .globl _device_not_available
- .globl _coprocessor_error
- .globl _divide_error
- .globl _debug
- .globl _nmi
- .globl _int3
- .globl _overflow
- .globl _bounds
- .globl _invalid_op
- .globl _double_fault
- .globl _coprocessor_segment_overrun
- .globl _invalid_TSS
- .globl _segment_not_present
- .globl _stack_segment
- .globl _general_protection
- .globl _reserved
- .globl _alignment_check
- .globl _page_fault
- .globl ret_from_sys_call
- .globl _sys_call_table
-
- .text
- .set noreorder
- .align 4
-handle_bottom_half:
- lw s0,_intr_count
- addiu s1,s0,1
- sw s1,_intr_count
- mfc0 t0,CP0_STATUS # Enable IRQs
- ori t0,t0,7
- xori t0,t0,6
- jal _do_bottom_half
- mtc0 t0,CP0_STATUS
- j 9f
- sw s1,_intr_count
-
- .set reorder
- .align 4
-reschedule:
- la ra,ret_from_sys_call
- j _schedule
-
- .set noreorder
- .align 4
-_system_call:
- li t1,NR_syscalls
- bge t0,t1,ret_from_sys_call
- .set nomacro
- li t2,-ENOSYS # must be single instruction!
- .set macro
- lui t1,_sys_call_table
- sll t0,t0,2
- addu t1,t0,t1
- lw t0,_sys_call_table(t1)
- lw s0,_current
-
- beq zero,t0,ret_from_sys_call
- lw t0,flags(s0)
- sll t0,t0,2 # PF_TRACESYS
- bltz t0,1f
- sw zero,errno(s0) # delay slot
-
- jal t0 # do the real work
- nop # fillme: delay slot
-
- sw v0,FR_REG2(sp) # save the return value
- lw v0,errno(s0)
- beq zero,v0,ret_from_sys_call
- subu v0,zero,v0 # v0 = -v0
- # fixme: indicate error
- j ret_from_sys_call
- sw v0,FR_REG2(sp)
-
- .align 4
-1: jal _syscall_trace
- nop
-#if 0
- movl ORIG_EAX(%esp),%eax
- call _sys_call_table(,%eax,4)
- movl %eax,EAX(%esp) # save the return value
- movl _current,%eax
- movl errno(%eax),%edx
- negl %edx
- je 1f
- movl %edx,EAX(%esp)
- orl $(CF_MASK),EFLAGS(%esp) # set carry to indicate error
-#endif
-1: jal _syscall_trace
- nop
-
- .align 4
-ret_from_sys_call:
- lw t0,_intr_count # bottom half
- bne zero,t0,2f
-
- lw t0,_bh_mask
- lw t1,_bh_active
- and t0,t0,t1
- bne zero,t0,handle_bottom_half
-9:
- mfc0 t0,CP0_STATUS # returning to supervisor ?
- andi t0,t0,30
- subu t0,t0,6
- bltz t0,2f
-
-1:
-#if 0
-/*
- * Try whether this is needed or not...
- */
- mfc0 t0,CP0_STATUS # enable irqs
- ori t0,t0,0x7
- xori t0,t0,0x6
- mtc0 t0,CP0_STATUS
-#endif
-
- lw t0,_need_resched
- bne zero,t0,reschedule
-
- lw t0,_current
- la t1,_task # task[0] cannot have signals
- lw t2,state(s0) # state
- beq t0,t1,2f
- lw t0,counter(s0) # counter
- beq zero,t2,reschedule # state == 0 ?
- lw a0,blocked(s0)
- # save blocked in a0 for
- # signal handling
- beq zero,t0,reschedule # counter == 0 ?
- lw t0,signal(s0)
- nor t1,zero,t0
- and t1,a0,t1
- beq zero,t1,skip_signal_return
- nop
-2:
- jal _do_signal
- move a1,sp
-
-skip_signal_return:
- .set noreorder
- .set noat
-return: RESTORE_ALL
- .set at
-
-/*
- * Assumptions for _handle_int:
- * - only bank a or b are possible interrupt sources
- */
- .globl _handle_int
-_handle_int:
- .set noreorder
- .text
- la s0,PORT_BASE
- li t1,0x0f
- sb t1,0x20(s0) # poll command
- lb t1,0x20(s0) # read result
- FILL_LDS
- bgtz t1,poll_second
- andi t1,t1,7
- /*
- * Acknowledge first pic
- */
- lb t2,0x21(s0)
- li s1,1
- sllv s1,s1,t1
- lb t4,_cache_21
- or t4,t4,s1
- sb t4,_cache_21
- sb t4,0x21(s0)
- li t4,0x20
- sb t4,0x20(s0)
- lw t0,_intr_count
- addiu t0,t0,1
- sw t0,_intr_count
- /*
- * Now call the real handler
- */
- la t0,_IRQ_vectors
- sll t2,t1,2
- addu t0,t0,t2
- lw t0,(t0)
- FILL_LDS
- jalr t0
- nop
- lw t0,_intr_count
- subu t0,t0,1
- sw t0,_intr_count
- /*
- * Unblock first pic
- */
-test1: lbu t1,0x21(s0) # tlbl exception?!?
- lb t1,_cache_21
- nor s1,zero,s1
- and t1,t1,s1
- sb t1,_cache_21
- jr v0
- sb t1,0x21(s0) # delay slot
-
- .set at
-poll_second:
- li t1,0x0f
- sb t1,0xa0(s0) # poll command
- lb t1,0xa0(s0) # read result
- FILL_LDS
- bgtz t1,spurious_interrupt
- andi t1,t1,7
- /*
- * Acknowledge second pic
- */
- lbu t2,0xa1(s0)
- lbu t3,_cache_A1
- li s1,1
- sllv s1,s1,t1
- or t3,t3,s1
- sb t3,_cache_A1
- sb t3,0xa1(s0)
- li t3,0x20
- sb t3,0xa0(s0)
- lw t0,_intr_count
- sb t3,0x20(s0)
- addiu t0,t0,1
- sw t0,_intr_count
- /*
- * Now call the real handler
- */
- la t0,_IRQ_vectors
- sll t2,t1,2
- addu t0,t0,t2
- lw t0,32(t0)
- FILL_LDS
- jalr t0
- nop
- lw t0,_intr_count
- subu t0,t0,1
- sw t0,_intr_count
- /*
- * Unblock second pic
- */
- lbu t1,0xa1(s0)
- lb t1,_cache_A1
- nor s1,zero,s1
- and t1,t1,s1
- sb t1,_cache_A1
- jr v0
- sb t1,0xa1(s0) # delay slot
-
- .set at
-spurious_interrupt:
- /*
- * Nothing happend... (whistle)
- */
- lw t0,_spurious_count
- la v0,return
- addiu t0,t0,1
- sw t0,_spurious_count
- jr ra
- nop
-
- .globl _IRQ
-_IRQ: move s2,ra
- mfc0 t0,CP0_STATUS
- ori t0,t0,0x1f
- xori t0,t0,0x1e
- mtc0 t0,CP0_STATUS
- move a1,sp
- jal _do_IRQ
- move a0,t1 # Delay slot
- mfc0 t0,CP0_STATUS
- ori t0,t0,1
- xori t0,t0,1
- la v0,ret_from_sys_call
- jr s2
- mtc0 t0,CP0_STATUS # Delay slot
-
- .globl _fast_IRQ
-_fast_IRQ: move s2,ra
- move a1,sp
- jal _do_fast_IRQ
- move a0,t1 # Delay slot
- la v0,return
- jr s2
- nop
-
- .globl _bad_IRQ
-_bad_IRQ:
- /*
- * Don't return & unblock the pic
- */
- j return
- nop
-
- .bss
- .globl _IRQ_vectors
-
-_IRQ_vectors:
- .fill 16,4,0
-
-/*
- * Dummy handlers
- */
- .text
- .set noreorder
- .set at
-
- .globl _handle_mod
-_handle_mod:
- la a0,mod_text
- j _panic
- nop
-
- .globl _handle_tlbl
-_handle_tlbl:
- la a0,badvaddr
- mfc0 a1,CP0_BADVADDR
- jal _printk
- nop
- la a0,status
- lw a1,FR_STATUS(sp)
- jal _printk
- nop
- la a0,eszero
- move a1,s0
- jal _printk
- nop
- la a0,espe
- move a1,sp
- jal _printk
- nop
- la a0,jifftext
- lw a1,_jiffies
- jal _printk
- nop
- la a0,inttext
- lw a1,_intr_count
- jal _printk
- nop
- la a0,tlbl_msg
- mfc0 a1,CP0_EPC
- jal _printk
- nop
- la a0,tlbl_text
- j _panic
- nop
-
- .data
-tlbl_msg: .asciz "tlbl exception at %x\n"
-badvaddr: .asciz "accessing %x\n"
-status: .asciz "cp0_status %x\n"
-eszero: .asciz "s0 %x\n"
-espe: .asciz "sp %x\n"
-jifftext: .asciz "jiffies %d\n"
-inttext: .asciz "IntNest: %d\n"
-
- .text
- .globl _handle_tlbs
-_handle_tlbs:
- la a0,tlbs_text
- j _panic
- nop
-
- .globl _handle_adel
-_handle_adel:
- la v0,adel_text
- jal _printk
- nop
- j _handle_tlbl
- la a0,adel_text
- j _panic
- nop
-
- .globl _handle_ades
-_handle_ades:
- la a0,ades_text
- j _panic
- nop
-
- .globl _handle_ibe
-_handle_ibe:
- la a0,ibe_text
- j _panic
- nop
-
- .globl _handle_dbe
-_handle_dbe:
- la a0,dbe_text
- j _panic
- nop
-
- .globl _handle_sys
-_handle_sys:
- la a0,sys_text
- j _panic
- nop
-
- .globl _handle_bp
-_handle_bp:
- la a0,bp_text
- j _panic
- nop
-
- .globl _handle_ri
-_handle_ri:
- la a0,ri_text
- j _panic
- nop
-
- .globl _handle_cpu
-_handle_cpu:
- la a0,cpu_text
- j _panic
- nop
-
- .globl _handle_ov
-_handle_ov:
- la a0,ov_text
- j _panic
- nop
-
- .globl _handle_tr
-_handle_tr:
- la a0,tr_text
- j _panic
- nop
-
- .globl _handle_reserved
-_handle_reserved:
- la a0,reserved_text
- j _panic
- nop
-
- .globl _handle_fpe
-_handle_fpe:
- la a0,fpe_text
- j _panic
- nop
-
- .data
-spurious_text: .asciz "Spurious interrupt"
-fpe_text: .asciz "fpe exception"
-reserved_text: .asciz "reserved exception"
-tr_text: .asciz "tr exception"
-ov_text: .asciz "ov exception"
-cpu_text: .asciz "cpu exception"
-ri_text: .asciz "ri exception"
-bp_text: .asciz "bp exception"
-sys_text: .asciz "sys exception"
-dbe_text: .asciz "dbe exception"
-ibe_text: .asciz "ibe exception"
-ades_text: .asciz "ades exception"
-adel_text: .asciz "adel exception"
-tlbs_text: .asciz "tlbs exception"
-mod_text: .asciz "mod exception"
-tlbl_text: .asciz "tlbl exception"
-
-/*
- * Exception handler table, 256 entries.
- */
- .data
- .globl _exception_handlers
-_exception_handlers:
- .word _handle_int /* 0 */
- .word _handle_mod
- .word _handle_tlbl
- .word _handle_tlbs
- .word _handle_adel
- .word _handle_ades
- .word _handle_ibe
- .word _handle_dbe
- .word _handle_sys
- .word _handle_bp
- .word _handle_ri
- .word _handle_cpu
- .word _handle_ov
- .word _handle_tr
- .word _handle_reserved
- .word _handle_fpe /* 15 */
-#if 0
- .fill 240,4,_handle_reserved
-#endif
-
-/*
- * Table of syscalls
- */
- .data
-_sys_call_table:
- .word _sys_setup /* 0 */
- .word _sys_exit
- .word _sys_fork
- .word _sys_read
- .word _sys_write
- .word _sys_open /* 5 */
- .word _sys_close
- .word _sys_waitpid
- .word _sys_creat
- .word _sys_link
- .word _sys_unlink /* 10 */
- .word _sys_execve
- .word _sys_chdir
- .word _sys_time
- .word _sys_mknod
- .word _sys_chmod /* 15 */
- .word _sys_chown
- .word _sys_break
- .word _sys_stat
- .word _sys_lseek
- .word _sys_getpid /* 20 */
- .word _sys_mount
- .word _sys_umount
- .word _sys_setuid
- .word _sys_getuid
- .word _sys_stime /* 25 */
- .word _sys_ptrace
- .word _sys_alarm
- .word _sys_fstat
- .word _sys_pause
- .word _sys_utime /* 30 */
- .word _sys_stty
- .word _sys_gtty
- .word _sys_access
- .word _sys_nice
- .word _sys_ftime /* 35 */
- .word _sys_sync
- .word _sys_kill
- .word _sys_rename
- .word _sys_mkdir
- .word _sys_rmdir /* 40 */
- .word _sys_dup
- .word _sys_pipe
- .word _sys_times
- .word _sys_prof
- .word _sys_brk /* 45 */
- .word _sys_setgid
- .word _sys_getgid
- .word _sys_signal
- .word _sys_geteuid
- .word _sys_getegid /* 50 */
- .word _sys_acct
- .word _sys_phys
- .word _sys_lock
- .word _sys_ioctl
- .word _sys_fcntl /* 55 */
- .word _sys_mpx
- .word _sys_setpgid
- .word _sys_ulimit
- .word _sys_olduname
- .word _sys_umask /* 60 */
- .word _sys_chroot
- .word _sys_ustat
- .word _sys_dup2
- .word _sys_getppid
- .word _sys_getpgrp /* 65 */
- .word _sys_setsid
- .word _sys_sigaction
- .word _sys_sgetmask
- .word _sys_ssetmask
- .word _sys_setreuid /* 70 */
- .word _sys_setregid
- .word _sys_sigsuspend
- .word _sys_sigpending
- .word _sys_sethostname
- .word _sys_setrlimit /* 75 */
- .word _sys_getrlimit
- .word _sys_getrusage
- .word _sys_gettimeofday
- .word _sys_settimeofday
- .word _sys_getgroups /* 80 */
- .word _sys_setgroups
- .word _sys_select
- .word _sys_symlink
- .word _sys_lstat
- .word _sys_readlink /* 85 */
- .word _sys_uselib
- .word _sys_swapon
- .word _sys_reboot
- .word _sys_readdir
- .word _sys_mmap /* 90 */
- .word _sys_munmap
- .word _sys_truncate
- .word _sys_ftruncate
- .word _sys_fchmod
- .word _sys_fchown /* 95 */
- .word _sys_getpriority
- .word _sys_setpriority
- .word _sys_profil
- .word _sys_statfs
- .word _sys_fstatfs /* 100 */
- .word _sys_ioperm
- .word _sys_socketcall
- .word _sys_syslog
- .word _sys_setitimer
- .word _sys_getitimer /* 105 */
- .word _sys_newstat
- .word _sys_newlstat
- .word _sys_newfstat
- .word _sys_uname
- .word _sys_iopl /* 110 */
- .word _sys_vhangup
- .word _sys_idle
- .word _sys_vm86
- .word _sys_wait4
- .word _sys_swapoff /* 115 */
- .word _sys_sysinfo
- .word _sys_ipc
- .word _sys_fsync
- .word _sys_sigreturn
- .word _sys_clone /* 120 */
- .word _sys_setdomainname
- .word _sys_newuname
- .word _sys_modify_ldt
- .word _sys_adjtimex
- .word _sys_mprotect /* 125 */
- .word _sys_sigprocmask
- .word _sys_create_module
- .word _sys_init_module
- .word _sys_delete_module
- .word _sys_get_kernel_syms /* 130 */
- .word _sys_quotactl
- .word _sys_getpgid
- .word _sys_fchdir
- .word _sys_bdflush
- .word _sys_sysfs /* 135 */
- .word _sys_personality
- .word 0 /* for afs_syscall */
- .word _sys_setfsuid
- .word _sys_setfsgid
- .word _sys_llseek /* 140 */
- .space (NR_syscalls-140)*4
diff --git a/arch/mips/ioport.c b/arch/mips/ioport.c
deleted file mode 100644
index ee3352410..000000000
--- a/arch/mips/ioport.c
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * linux/arch/mips/ioport.c
- *
- * Functions not implemented for Linux/MIPS
- */
-#include <linux/linkage.h>
-#include <linux/errno.h>
-
-asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
-{
- return -ENOSYS;
-}
-
-asmlinkage int sys_iopl(long ebx,long ecx,long edx,
- long esi, long edi, long ebp, long eax, long ds,
- long es, long fs, long gs, long orig_eax,
- long eip,long cs,long eflags,long esp,long ss)
-{
- return -ENOSYS;
-}
diff --git a/arch/mips/irq.S b/arch/mips/irq.S
deleted file mode 100644
index 129c2843f..000000000
--- a/arch/mips/irq.S
+++ /dev/null
@@ -1,642 +0,0 @@
-/*
- * linux/kernel/mips/sys_call.S
- *
- * Copyright (C) 1994 Waldorf GMBH
- * written by Ralf Baechle
- */
-
-/*
- * All code below must be relocatable!
- */
-
-/*
- * sys_call.S contains the system-call and fault low-level handling routines.
- * This also contains the timer-interrupt handler, as well as all interrupts
- * and faults that can result in a task-switch.
- *
- * NOTE: This code handles signal-recognition, which happens every time
- * after a timer-interrupt and after each system call.
- *
- * I changed all the .align's to 4 (16 byte alignment), as that's faster
- * on a 486.
- *
- * Stack layout in 'ret_from_system_call':
- * ptrace needs to have all regs on the stack.
- * if the order here is changed, it needs to be
- * updated in fork.c:copy_process, signal.c:do_signal,
- * ptrace.c and ptrace.h
- *
- * 0(%esp) - %ebx
- * 4(%esp) - %ecx
- * 8(%esp) - %edx
- * C(%esp) - %esi
- * 10(%esp) - %edi
- * 14(%esp) - %ebp
- * 18(%esp) - %eax
- * 1C(%esp) - %ds
- * 20(%esp) - %es
- * 24(%esp) - %fs
- * 28(%esp) - %gs
- * 2C(%esp) - orig_eax
- * 30(%esp) - %eip
- * 34(%esp) - %cs
- * 38(%esp) - %eflags
- * 3C(%esp) - %oldesp
- * 40(%esp) - %oldss
- */
-
-#include <linux/segment.h>
-#include <linux/sys.h>
-
-/*
- * Offsets into the Interrupt stackframe.
- */
-FR_REG1 = 0
-FR_REG2 = 4
-FR_REG3 = 8
-FR_REG4 = 12
-FR_REG5 = 16
-FR_REG6 = 20
-FR_REG7 = 24
-FR_REG8 = 28
-FR_REG9 = 32
-FR_REG10 = 36
-FR_REG11 = 40
-FR_REG12 = 44
-FR_REG13 = 48
-FR_REG14 = 52
-FR_REG15 = 56
-FR_REG16 = 60
-FR_REG17 = 64
-FR_REG18 = 68
-FR_REG19 = 72
-FR_REG20 = 76
-FR_REG21 = 80
-FR_REG22 = 84
-FR_REG23 = 88
-FR_REG24 = 92
-FR_REG25 = 96
-/* $26 and $27 not saved */
-FR_REG28 = 100
-FR_REG29 = 104
-FR_REG30 = 108
-FR_REG31 = 112
-/*
- * Saved cp0 registers follow
- */
-FR_STATUS = 116
-FR_EPC = 120
-FR_ERROREPC = 124
-FR_SIZE = 120 /* Size of stack frame */
-
-/*
- * These are offsets into the task-struct.
- */
-state = 0
-counter = 4
-priority = 8
-signal = 12
-blocked = 16
-flags = 20
-errno = 24
-dbgreg6 = 52
-dbgreg7 = 56
-exec_domain = 60
-
-ENOSYS = 38
-
- .globl _system_call,_lcall7
- .globl _device_not_available, _coprocessor_error
- .globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,
- .globl _invalid_op,_double_fault,_coprocessor_segment_overrun
- .globl _invalid_TSS,_segment_not_present,_stack_segment
- .globl _general_protection,_reserved
- .globl _alignment_check,_page_fault
- .globl ret_from_sys_call, _sys_call_table
-
-#define SAVE_ALL(which_pc) \
- .set noreorder \
- .set noat \
- lui k0,0x8000 \
- move k1,$sp \
- lw sp,_kernelsp-except_vec0(k0) \
- subu sp,$sp,FR_SIZE \
- sw sp,_kernelsp-except_vec0(k0) \ /* Kernel SP */
- mfc0 v0,CP0_STATUS \
- sw v0,FR_STATUS(sp) \
- mfc0 v0,CP0_EPC \
- sw v0,FR_EPC \
- mfc0 v0,CP0_ERROREPC \
- sw v0,FR_ERROREPC \
- sw k1,FR_R27(sp) \
- sw $2,FR_R1(sp) \
- sw $2,FR_R2(sp) \
- sw $3,FR_R3(sp) \
- sw $4,FR_R4(sp) \
- sw $5,FR_R5(sp) \
- sw $6,FR_R6(sp) \
- sw $7,FR_R7(sp) \
- sw $8,FR_R8(sp) \
- sw $9,FR_R9(sp) \
- sw $10,FR_R10(sp) \
- sw $11,FR_R11(sp) \
- sw $12,FR_R12(sp) \
- sw $13,FR_R13(sp) \
- sw $14,FR_R14(sp) \
- sw $15,FR_R15(sp) \
- sw $16,FR_R16(sp) \
- sw $17,FR_R17(sp) \
- sw $18,FR_R18(sp) \
- sw $19,FR_R19(sp) \
- sw $20,FR_R20(sp) \
- sw $21,FR_R21(sp) \
- sw $22,FR_R22(sp) \
- sw $23,FR_R23(sp) \
- sw $24,FR_R24(sp) \
- sw $25,FR_R25(sp) \
- sw $28,FR_R28(sp) \
- sw $30,FR_R30(sp) \
- sw $31,FR_R31(sp)
-
-
-#define RESTORE_ALL \
- lui k1,0x8000 \
- move k0,$sp \
- lw v0,FR_ERROREPC(k0) \
- lw v1,FR_EPC(k0) \
- mtc0 v0,CP0_ERROREPC(k0) \
- mtc0 v1,CP0_EPC(k0) \
- lw $31,FR_R31(k0) \
- lw $30,FR_R30(k0) \
- lw $28,FR_R28(k0) \
- lw $25,FR_R25(k0) \
- lw $24,FR_R24(k0) \
- lw $23,FR_R23(k0) \
- lw $22,FR_R22(k0) \
- lw $21,FR_R21(k0) \
- lw $20,FR_R20(k0) \
- lw $19,FR_R19(k0) \
- lw $18,FR_R18(k0) \
- lw $17,FR_R17(k0) \
- lw $16,FR_R16(k0) \
- lw $15,FR_R15(k0) \
- lw $14,FR_R14(k0) \
- lw $13,FR_R13(k0) \
- lw $12,FR_R12(k0) \
- lw $11,FR_R11(k0) \
- lw $10,FR_R10(k0) \
- lw $9,FR_R9(k0) \
- lw $8,FR_R8(k0) \
- lw $7,FR_R7(k0) \
- lw $6,FR_R6(k0) \
- lw $5,FR_R5(k0) \
- lw $4,FR_R4(k0) \
- lw $3,FR_R3(k0) \
- lw $2,FR_R2(k0) \
- lw $1,FR_R1(k0) \
- addiu k0,k0,FR_SIZE \
- sw k0,_kernelsp-except_vec0(k1) \ /* Kernel SP */
- eret
-
- .align 4
-handle_bottom_half:
- pushfl
- incl _intr_count
- mtc0 zero,CP0_STATUS
- call _do_bottom_half
- popfl
- decl _intr_count
- j 9f
- nop
-
- .align 4
-reschedule:
- pushl $ret_from_sys_call
- j _schedule
- nop
-
- .align 4
-_system_call:
- pushl %eax # save orig_eax
- SAVE_ALL
- movl $-ENOSYS,EAX(%esp)
- cmpl $(NR_syscalls),%eax
- jae ret_from_sys_call
- movl _sys_call_table(,%eax,4),%eax
- testl %eax,%eax
- je ret_from_sys_call
- movl _current,%ebx
- andl $~CF_MASK,EFLAGS(%esp) # clear carry - assume no errors
- movl $0,errno(%ebx)
- movl %db6,%edx
- movl %edx,dbgreg6(%ebx) # save current hardware debugging status
- testb $0x20,flags(%ebx) # PF_TRACESYS
- jne 1f
- call *%eax
- movl %eax,EAX(%esp) # save the return value
- movl errno(%ebx),%edx
- negl %edx
- je ret_from_sys_call
- movl %edx,EAX(%esp)
- orl $(CF_MASK),EFLAGS(%esp) # set carry to indicate error
- j ret_from_sys_call
- nop
-
- .align 4
-1: call _syscall_trace
- movl ORIG_EAX(%esp),%eax
- call _sys_call_table(,%eax,4)
- movl %eax,EAX(%esp) # save the return value
- movl _current,%eax
- movl errno(%eax),%edx
- negl %edx
- je 1f
- movl %edx,EAX(%esp)
- orl $(CF_MASK),EFLAGS(%esp) # set carry to indicate error
-1: call _syscall_trace
-
- .align 4,0x90
-ret_from_sys_call:
- cmpl $0,_intr_count
- jne 2f
- movl _bh_mask,%eax
- andl _bh_active,%eax
- jne handle_bottom_half
-9: movl EFLAGS(%esp),%eax # check VM86 flag: CS/SS are
- testl $(VM_MASK),%eax # different then
- jne 1f
- cmpw $(KERNEL_CS),CS(%esp) # was old code segment supervisor ?
- je 2f
-1: sti
- orl $(IF_MASK),%eax # these just try to make sure
- andl $~NT_MASK,%eax # the program doesn't do anything
- movl %eax,EFLAGS(%esp) # stupid
- cmpl $0,_need_resched
- jne reschedule
- movl _current,%eax
- cmpl _task,%eax # task[0] cannot have signals
- je 2f
- cmpl $0,state(%eax) # state
- jne reschedule
- cmpl $0,counter(%eax) # counter
- je reschedule
- movl blocked(%eax),%ecx
- movl %ecx,%ebx # save blocked in %ebx for
- # signal handling
- notl %ecx
- andl signal(%eax),%ecx
- jne signal_return
-2: RESTORE_ALL
-
- .align 4
-signal_return:
- movl %esp,%ecx
- pushl %ecx
- testl $(VM_MASK),EFLAGS(%ecx)
- jne v86_signal_return
- pushl %ebx
- call _do_signal
- popl %ebx
- popl %ebx
- RESTORE_ALL
-
- .align 4
-v86_signal_return:
- call _save_v86_state
- movl %eax,%esp
- pushl %eax
- pushl %ebx
- call _do_signal
- popl %ebx
- popl %ebx
- RESTORE_ALL
-
- .align 4
-_divide_error:
- move $a1,zero # no error code
- la $t0,$_do_divide_error
- .align 4,0x90
-error_code:
- push %fs
- push %es
- push %ds
- pushl %eax
- pushl %ebp
- pushl %edi
- pushl %esi
- pushl %edx
- pushl %ecx
- pushl %ebx
- cld
- movl $-1, %eax
- xchgl %eax, ORIG_EAX(%esp) # orig_eax (get the error code. )
- xorl %ebx,%ebx # zero ebx
- mov %gs,%bx # get the lower order bits of gs
- xchgl %ebx, GS(%esp) # get the address and save gs.
- pushl %eax # push the error code
- lea 4(%esp),%edx
- pushl %edx
- movl $(KERNEL_DS),%edx
- mov %dx,%ds
- mov %dx,%es
- movl $(USER_DS),%edx
- mov %dx,%fs
- jal t0 # call handler
- addl $8,%esp
- j ret_from_sys_call
-
- .align 4
-_coprocessor_error:
- move a1,zero
- la t0,_do_coprocessor_error
- j error_code
-
- .align 4
-_device_not_available:
- pushl $-1 # mark this as an int
- SAVE_ALL
- pushl $ret_from_sys_call
- movl %cr0,%eax
- testl $0x4,%eax # EM (math emulation bit)
- je _math_state_restore
- pushl $0 # temporary storage for ORIG_EIP
- call _math_emulate
- addl $4,%esp
- ret
-
- .set reorder
-
- .align 4
-_debug:
- move a1,zero
- la t0,_do_debug
- j error_code
-
- .align 4
-_nmi:
- move a1,zero
- la t0,_do_nmi
- j error_code
-
- .align 4
-_int3:
- move a1,zero
- la t0,_do_int3
- j error_code
-
- .align 4
-_overflow:
- move a1,zero
- la t0,_do_overflow
- j error_code
-
- .align 4
-_bounds:
- move a1,zero
- la t0,_do_bounds
- j error_code
-
- .align 4
-_invalid_op:
- move a1,zero
- la t0,_do_invalid_op
- j error_code
-
- .align 4
-_segment_not_present:
- la t0,_do_segment_not_present
- j error_code
-
- .align 4
-_stack_segment:
- la t0,_do_stack_segment
- j error_code
-
- .align 4
-_general_protection:
- la t0,_do_general_protection
- j error_code
-
- .align 4
-_page_fault:
- la t0,_do_page_fault
- j error_code
-/*
- * TLB Refill exception entry point
- *
- * The mm data is stored in the context register and
- */
- .text
- .set noreorder
- .set noat
- dmfc0 k0,CP0_CONTEXT
- dsrl k0,k0,2
- lw k0,(k0) # Level 1 descriptor
- dmfc0 k1,CP0_BADVADDR
- srl k1,k1,10
- andi k1,k1,0xffc
- addu k1,k1,k1
- lwu k0,(k1) # 2 Level 2 entries
- lwu k1,4(k1)
- dmtc0 k0,CP0_ENTRYLO0
- dmtc0 k0,CP0_ENTRYLO1
- tlbwr
- /*
- * Now compute the return address. Since this is extremly
- * timecritical the code is inlined
- */
- mfc0 k0,CP0_CAUSE
- bgtz k0,1f
-
- /*
- * Damn - a branch delay slot. Compute new PC
- */
-
- /*
- * That's it boys - back to work!
- */
-1: eret
-
-
-
-
- lui t0,>_exception_handlers
- mfc0 t1,CP0_CAUSE
- andi t1,t1,0x3fc
- addu t0,t0,t1
- lw t0,<_exception_handlers(t0)
- sw /* fill delay slot */
- jalr t0
- sw /* fill delay slot */
-
-
-/*
- * Exception handler table, 256 entries.
- */
- .data
- .align 4
-_exception_handlers:
- .word _handle_int /* 0 */
- .word _handle_mod
- .word _handle_tlbl
- .word _handle_tlbs
- .word _handle_adel
- .word _handle_ades
- .word _handle_ibe
- .word _handle_dbe
- .word _handle_sys
- .word _handle_bp
- .word _handle_ri
- .word _handle_cpu
- .word _handle_ov
- .word _handle_tr
- .word _handle_reserved
- .word _handle_fpe
- .fill 240,4,_handle_reserved /* 16 */
-
-/*
- * Table of syscalls
- */
- .data
- .align 4
-_sys_call_table:
- .word _sys_setup /* 0 */
- .word _sys_exit
- .word _sys_fork
- .word _sys_read
- .word _sys_write
- .word _sys_open /* 5 */
- .word _sys_close
- .word _sys_wordpid
- .word _sys_creat
- .word _sys_link
- .word _sys_unlink /* 10 */
- .word _sys_execve
- .word _sys_chdir
- .word _sys_time
- .word _sys_mknod
- .word _sys_chmod /* 15 */
- .word _sys_chown
- .word _sys_break
- .word _sys_stat
- .word _sys_lseek
- .word _sys_getpid /* 20 */
- .word _sys_mount
- .word _sys_umount
- .word _sys_setuid
- .word _sys_getuid
- .word _sys_stime /* 25 */
- .word _sys_ptrace
- .word _sys_alarm
- .word _sys_fstat
- .word _sys_pause
- .word _sys_utime /* 30 */
- .word _sys_stty
- .word _sys_gtty
- .word _sys_access
- .word _sys_nice
- .word _sys_ftime /* 35 */
- .word _sys_sync
- .word _sys_kill
- .word _sys_rename
- .word _sys_mkdir
- .word _sys_rmdir /* 40 */
- .word _sys_dup
- .word _sys_pipe
- .word _sys_times
- .word _sys_prof
- .word _sys_brk /* 45 */
- .word _sys_setgid
- .word _sys_getgid
- .word _sys_signal
- .word _sys_geteuid
- .word _sys_getegid /* 50 */
- .word _sys_acct
- .word _sys_phys
- .word _sys_lock
- .word _sys_ioctl
- .word _sys_fcntl /* 55 */
- .word _sys_mpx
- .word _sys_setpgid
- .word _sys_ulimit
- .word _sys_olduname
- .word _sys_umask /* 60 */
- .word _sys_chroot
- .word _sys_ustat
- .word _sys_dup2
- .word _sys_getppid
- .word _sys_getpgrp /* 65 */
- .word _sys_setsid
- .word _sys_sigaction
- .word _sys_sgetmask
- .word _sys_ssetmask
- .word _sys_setreuid /* 70 */
- .word _sys_setregid
- .word _sys_sigsuspend
- .word _sys_sigpending
- .word _sys_sethostname
- .word _sys_setrlimit /* 75 */
- .word _sys_getrlimit
- .word _sys_getrusage
- .word _sys_gettimeofday
- .word _sys_settimeofday
- .word _sys_getgroups /* 80 */
- .word _sys_setgroups
- .word _sys_select
- .word _sys_symlink
- .word _sys_lstat
- .word _sys_readlink /* 85 */
- .word _sys_uselib
- .word _sys_swapon
- .word _sys_reboot
- .word _sys_readdir
- .word _sys_mmap /* 90 */
- .word _sys_munmap
- .word _sys_truncate
- .word _sys_ftruncate
- .word _sys_fchmod
- .word _sys_fchown /* 95 */
- .word _sys_getpriority
- .word _sys_setpriority
- .word _sys_profil
- .word _sys_statfs
- .word _sys_fstatfs /* 100 */
- .word _sys_ioperm
- .word _sys_socketcall
- .word _sys_syslog
- .word _sys_setitimer
- .word _sys_getitimer /* 105 */
- .word _sys_newstat
- .word _sys_newlstat
- .word _sys_newfstat
- .word _sys_uname
- .word _sys_iopl /* 110 */
- .word _sys_vhangup
- .word _sys_idle
- .word _sys_vm86
- .word _sys_word4
- .word _sys_swapoff /* 115 */
- .word _sys_sysinfo
- .word _sys_ipc
- .word _sys_fsync
- .word _sys_sigreturn
- .word _sys_clone /* 120 */
- .word _sys_setdomainname
- .word _sys_newuname
- .word _sys_modify_ldt
- .word _sys_adjtimex
- .word _sys_mprotect /* 125 */
- .word _sys_sigprocmask
- .word _sys_create_module
- .word _sys_init_module
- .word _sys_delete_module
- .word _sys_get_kernel_syms /* 130 */
- .word _sys_quotactl
- .word _sys_getpgid
- .word _sys_fchdir
- .word _sys_bdflush
- .word _sys_sysfs /* 135 */
- .word _sys_personality
- .word 0 /* for afs_syscall */
-
- .space (NR_syscalls-137)*4
diff --git a/arch/mips/irq.c b/arch/mips/irq.c
deleted file mode 100644
index 1bce3d07a..000000000
--- a/arch/mips/irq.c
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * linux/kernel/irq.c
- *
- * Copyright (C) 1992 Linus Torvalds
- *
- * This file contains the code used by various IRQ handling routines:
- * asking for different IRQ's should be done through these routines
- * instead of just grabbing them. Thus setups with different IRQ numbers
- * shouldn't result in any weird surprises, and installing new handlers
- * should be easier.
- */
-
-/*
- * IRQ's are in fact implemented a bit like signal handlers for the kernel.
- * The same sigaction struct is used, and with similar semantics (ie there
- * is a SA_INTERRUPT flag etc). Naturally it's not a 1:1 relation, but there
- * are similarities.
- *
- * sa_handler(int irq_NR) is the default function called (0 if no).
- * sa_mask is horribly ugly (I won't even mention it)
- * sa_flags contains various info: SA_INTERRUPT etc
- * sa_restorer is the unused
- */
-
-#include <linux/ptrace.h>
-#include <linux/errno.h>
-#include <linux/kernel_stat.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#define CR0_NE 32
-
-unsigned char cache_21 = 0xff;
-unsigned char cache_A1 = 0xff;
-
-unsigned long intr_count = 0;
-unsigned long spurious_count = 0;
-unsigned long bh_active = 0;
-unsigned long bh_mask = 0xFFFFFFFF;
-struct bh_struct bh_base[32];
-
-void disable_irq(unsigned int irq_nr)
-{
- unsigned long flags;
- unsigned char mask;
-
- mask = 1 << (irq_nr & 7);
- save_flags(flags);
- if (irq_nr < 8) {
- cli();
- cache_21 |= mask;
- outb(cache_21,0x21);
- restore_flags(flags);
- return;
- }
- cli();
- cache_A1 |= mask;
- outb(cache_A1,0xA1);
- restore_flags(flags);
-}
-
-void enable_irq(unsigned int irq_nr)
-{
- unsigned long flags;
- unsigned char mask;
-
- mask = ~(1 << (irq_nr & 7));
- save_flags(flags);
- if (irq_nr < 8) {
- cli();
- cache_21 &= mask;
- outb(cache_21,0x21);
- restore_flags(flags);
- return;
- }
- cli();
- cache_A1 &= mask;
- outb(cache_A1,0xA1);
- restore_flags(flags);
-}
-
-/*
- * do_bottom_half() runs at normal kernel priority: all interrupts
- * enabled. do_bottom_half() is atomic with respect to itself: a
- * bottom_half handler need not be re-entrant.
- */
-asmlinkage void do_bottom_half(void)
-{
- unsigned long active;
- unsigned long mask, left;
- struct bh_struct *bh;
-
- bh = bh_base;
- active = bh_active & bh_mask;
- for (mask = 1, left = ~0 ; left & active ; bh++,mask += mask,left += left) {
- if (mask & active) {
- void (*fn)(void *);
- bh_active &= ~mask;
- fn = bh->routine;
- if (!fn)
- goto bad_bh;
- fn(bh->data);
- }
- }
- return;
-bad_bh:
- printk ("irq.c:bad bottom half entry\n");
-}
-
-/*
- * Pointers to the low-level handlers: first the general ones, then the
- * fast ones, then the bad ones.
- */
-extern void IRQ(void);
-extern void fast_IRQ(void);
-extern void bad_IRQ(void);
-
-/*
- * Initial irq handlers.
- */
-static struct sigaction irq_sigaction[16] = {
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }
-};
-
-int get_irq_list(char *buf)
-{
- int i, len = 0;
- struct sigaction * sa = irq_sigaction;
-
- for (i = 0 ; i < 16 ; i++, sa++) {
- if (!sa->sa_handler)
- continue;
- len += sprintf(buf+len, "%2d: %8d %c %s\n",
- i, kstat.interrupts[i],
- (sa->sa_flags & SA_INTERRUPT) ? '+' : ' ',
- (char *) sa->sa_mask);
- }
- return len;
-}
-
-/*
- * do_IRQ handles IRQ's that have been installed without the
- * SA_INTERRUPT flag: it uses the full signal-handling return
- * and runs with other interrupts enabled. All relatively slow
- * IRQ's should use this format: notably the keyboard/timer
- * routines.
- */
-asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
-{
- struct sigaction * sa = irq + irq_sigaction;
-
- kstat.interrupts[irq]++;
- sa->sa_handler((int) regs);
-}
-
-/*
- * do_fast_IRQ handles IRQ's that don't need the fancy interrupt return
- * stuff - the handler is also running with interrupts disabled unless
- * it explicitly enables them later.
- */
-asmlinkage void do_fast_IRQ(int irq)
-{
- struct sigaction * sa = irq + irq_sigaction;
-
- kstat.interrupts[irq]++;
- sa->sa_handler(irq);
-}
-
-/*
- * Using "struct sigaction" is slightly silly, but there
- * are historical reasons and it works well, so..
- */
-static int irqaction(unsigned int irq, struct sigaction * new_sa)
-{
- struct sigaction * sa;
- unsigned long flags;
-
- if (irq > 15)
- return -EINVAL;
- sa = irq + irq_sigaction;
- if (sa->sa_handler)
- return -EBUSY;
- if (!new_sa->sa_handler)
- return -EINVAL;
- save_flags(flags);
- cli();
- *sa = *new_sa;
- /*
- * FIXME: Does the SA_INTERRUPT flag make any sense on the MIPS???
- */
- if (sa->sa_flags & SA_INTERRUPT)
- set_intr_gate(irq,fast_IRQ);
- else
- set_intr_gate(irq,IRQ);
- if (irq < 8) {
- cache_21 &= ~(1<<irq);
- outb(cache_21,0x21);
- } else {
- cache_21 &= ~(1<<2);
- cache_A1 &= ~(1<<(irq-8));
- outb(cache_21,0x21);
- outb(cache_A1,0xA1);
- }
- restore_flags(flags);
- return 0;
-}
-
-int request_irq(unsigned int irq, void (*handler)(int),
- unsigned long flags, const char * devname)
-{
- struct sigaction sa;
-
- sa.sa_handler = handler;
- sa.sa_flags = flags;
- sa.sa_mask = (unsigned long) devname;
- sa.sa_restorer = NULL;
- return irqaction(irq,&sa);
-}
-
-void free_irq(unsigned int irq)
-{
- struct sigaction * sa = irq + irq_sigaction;
- unsigned long flags;
-
- if (irq > 15) {
- printk("Trying to free IRQ%d\n",irq);
- return;
- }
- if (!sa->sa_handler) {
- printk("Trying to free free IRQ%d\n",irq);
- return;
- }
- save_flags(flags);
- cli();
- if (irq < 8) {
- cache_21 |= 1 << irq;
- outb(cache_21,0x21);
- } else {
- cache_A1 |= 1 << (irq-8);
- outb(cache_A1,0xA1);
- }
- set_intr_gate(irq,bad_IRQ);
- sa->sa_handler = NULL;
- sa->sa_flags = 0;
- sa->sa_mask = 0;
- sa->sa_restorer = NULL;
- restore_flags(flags);
-}
-
-#if 0
-/*
- * handle fpa errors
- */
-static void math_error_irq(int cpl)
-{
- if (!hard_math)
- return;
- handle_fpe();
-}
-#endif
-
-static void no_action(int cpl) { }
-
-void init_IRQ(void)
-{
- int i;
-
- for (i = 0; i < 16 ; i++)
- set_intr_gate(i, bad_IRQ[i]);
- if (request_irq(2, no_action, SA_INTERRUPT, "cascade"))
- printk("Unable to get IRQ2 for cascade\n");
-
- /* initialize the bottom half routines. */
- for (i = 0; i < 32; i++) {
- bh_base[i].routine = NULL;
- bh_base[i].data = NULL;
- }
- bh_active = 0;
- intr_count = 0;
-}
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
new file mode 100644
index 000000000..0086f60cf
--- /dev/null
+++ b/arch/mips/kernel/Makefile
@@ -0,0 +1,94 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+.c.s:
+ $(CC) $(CFLAGS) -S $<
+.s.o:
+ $(AS) $(ASFLAGS) -o $*.o $<
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+.S.s:
+ $(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+ $(CC) $(CFLAGS) -c $< -o $*.o
+
+OBJS = process.o signal.o entry.o traps.o irq.o ptrace.o vm86.o ioport.o \
+ setup.o bios32.o tynedma.o
+
+include ../../../.config
+
+#
+# Kernel debugging
+#
+
+ifdef CONFIG_REMOTE_DEBUG
+OBJS += gdb-low.o gdb-stub.o
+endif
+
+#
+# Board specific code
+#
+
+ifdef CONFIG_MIPS_JAZZ
+OBJS += jazzdma.o
+endif
+
+ifdef CONFIG_ACER_PICA_61
+OBJS += pica.o
+endif
+
+ifdef CONFIG_DESKSTATION_TYNE
+OBJS += tyne.o
+endif
+
+ifdef CONFIG_MIPS_MAGNUM_4000
+OBJS += magnum4000.o
+endif
+
+#
+# CPU model specific code
+#
+ifdef CONFIG_CPU_R4X00
+OBJS += r4xx0.o
+endif
+
+ifdef CONFIG_CPU_R4600
+OBJS += r4xx0.o
+endif
+
+all: kernel.o head.o
+
+entry.o: entry.S
+
+head.o: head.S
+
+magnum4000.o: magnum4000.S
+
+pica.o: pica.S
+
+r4xx0.o: r4xx0.S
+
+tyne.o: tyne.S
+
+kernel.o: $(OBJS)
+ $(LD) -r -o kernel.o $(OBJS)
+ sync
+
+dep:
+ $(CPP) -M *.[cS] > .depend
+
+modules:
+
+dummy:
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/arch/mips/kernel/bios32.c b/arch/mips/kernel/bios32.c
new file mode 100644
index 000000000..1fe61faa0
--- /dev/null
+++ b/arch/mips/kernel/bios32.c
@@ -0,0 +1,7 @@
+/*
+ * bios 32 replacement
+ */
+unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
+{
+ return memory_start;
+}
diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S
new file mode 100644
index 000000000..787e2bbf4
--- /dev/null
+++ b/arch/mips/kernel/entry.S
@@ -0,0 +1,625 @@
+/*
+ * arch/mips/kernel/entry.S
+ *
+ * Copyright (C) 1994, 1995 Waldorf Electronics
+ * written by Ralf Baechle and Andreas Busse
+ */
+
+/*
+ * entry.S contains the system-call and fault low-level handling routines.
+ * This also contains the timer-interrupt handler, as well as all interrupts
+ * and faults that can result in a task-switch. The ISA dependend TLB
+ * code is in arch/mips/kernel/tlb.S
+ */
+
+#include <linux/sys.h>
+
+#include <asm/asm.h>
+#include <asm/errno.h>
+#include <asm/segment.h>
+#include <asm/mipsregs.h>
+#include <asm/mipsconfig.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/stackframe.h>
+#include <asm/processor.h>
+
+/*
+ * These are offsets into the task-struct.
+ */
+state = 0
+counter = 4
+priority = 8
+signal = 12
+blocked = 16
+flags = 20
+errno = 24
+exec_domain = 60
+
+ .text
+ .set noreorder
+ .align 4
+handle_bottom_half:
+ lui s0,%hi(intr_count)
+ lw s1,%lo(intr_count)(s0)
+ mfc0 s3,CP0_STATUS # Enable IRQs
+ addiu s2,s1,1
+ sw s2,%lo(intr_count)(s0)
+ ori t0,s3,0x1f
+ xori t0,0x1e
+ jal do_bottom_half
+ mtc0 t0,CP0_STATUS # delay slot
+ mtc0 s3,CP0_STATUS # Restore old IRQ state
+ j 9f
+ sw s1,%lo(intr_count)(s0) # delay slot
+
+reschedule:
+ lui ra,%hi(ret_from_sys_call)
+ j schedule
+ addiu ra,%lo(ret_from_sys_call) # delay slot
+
+ .align 5
+ NESTED(handle_sys, FR_SIZE, sp)
+ .set noat
+ SAVE_ALL
+ STI
+ .set at
+ /*
+ * Compute return address. We assume that syscalls never
+ * appear in delay slots. For the Linux/MIPS libc this
+ * assumption is always true.
+ */
+ lw t3,FR_EPC(sp)
+ lw s1,FR_REG2(sp)
+ li t0,-ENOSYS
+ addiu t3,4
+ sw t3,FR_EPC(sp)
+ li t2,NR_syscalls
+ bge s1,t2,ret_from_sys_call
+ sw t0,FR_REG2(sp) # delay slot
+ sll s1,PTRLOG
+ lw s1,sys_call_table(s1)
+ lw s0,current
+
+ beqz s1,ret_from_sys_call
+ lw t0,flags(s0) # delay slot
+ sll t0,26 # PF_TRACESYS
+ bltz t0,1f
+ sw zero,errno(s0) # delay slot
+
+#if 0
+ lw t0,FR_ORIG_REG2(sp)
+ beq t0,4,1f
+ nop
+ la t0,sys_call_names
+ lw t1,FR_ORIG_REG2(sp)
+ sll t1,2
+ addu t0,t1
+ lw a1,(t0)
+ PRINT("%s(")
+ lw a1,FR_REG4(sp)
+ lw a2,FR_REG5(sp)
+ lw a3,FR_REG6(sp)
+ PRINT("%08lx, %08lx, %08lx, ")
+ lw a1,FR_REG7(sp)
+ lw a2,FR_EPC(sp)
+ lw a3,FR_REG31(sp)
+ PRINT("%08lx) epc %08lx ra %08lx ")
+1:
+#endif
+ lw a0,FR_REG4(sp)
+ lw a1,FR_REG5(sp)
+ lw a2,FR_REG6(sp)
+ lw a3,FR_REG7(sp)
+ lw t0,FR_REG3(sp)
+ jalr s1 # do the real work
+ sw t0,PTRSIZE*4(sp) # delay slot
+
+#if 0
+ lw t0,FR_ORIG_REG2(sp)
+ beq t0,4,1f
+ nop
+ sw v0,xxx
+ lw a1,xxx
+ PRINT("res %08lx\n")
+ lw v0,xxx
+ .data
+xxx: .word 0
+ .text
+1:
+#endif
+
+ lw t0,errno(s0)
+ sw v0,FR_REG2(sp) # save return value
+ subu t0,zero,t0
+ beqz t0,ret_from_sys_call
+ nop # delay slot
+ /*
+ * Fixme: should set error flag
+ */
+ j ret_from_sys_call
+ sw t0,FR_REG2(sp) # delay slot
+
+ .align 4
+1: jal syscall_trace
+ nop # delay slot
+
+ lw a0,FR_REG4(sp)
+ lw a1,FR_REG5(sp)
+ lw a2,FR_REG6(sp)
+ lw a3,FR_REG7(sp)
+ lw t0,FR_REG3(sp)
+ jalr s1 # do the real work
+ sw t0,PTRSIZE*4(sp) # delay slot
+
+ lw t0,errno(s0)
+ sw v0,FR_REG2(sp)
+ subu t0,zero,t0 # delay slot
+ beqz t0,1f
+ nop # delay slot
+ /*
+ * Fixme: should set error flag
+ */
+1: jal syscall_trace
+ sw t0,FR_REG2(sp) # delay slot
+
+ .align 4
+ .globl ret_from_sys_call
+ret_from_sys_call:
+ lw t0,intr_count # bottom half
+ bnez t0,return
+9:
+ lw t0,bh_mask # delay slot
+ lw t1,bh_active # unused delay slot
+ and t0,t1
+ bnez t0,handle_bottom_half
+
+ lw t0,FR_STATUS(sp) # returning to kernel mode?
+ andi t1,t0,0x10
+ beqz t1,return # -> yes
+
+ mfc0 t0,CP0_STATUS # delay slot
+ lw t1,need_resched
+ ori t0,0x1f # enable irqs
+ xori t0,0x1e
+ bnez t1,reschedule
+ mtc0 t0,CP0_STATUS # delay slot
+
+ lw s0,current
+ lw t0,task
+ lw t1,state(s0) # state
+ beq s0,t0,return # task[0] cannot have signals
+ lw t0,counter(s0) # counter
+ bnez t1,reschedule # state == 0 ?
+ lw a0,blocked(s0)
+ # save blocked in a0 for
+ # signal handling
+ beqz t0,reschedule # counter == 0 ?
+ lw t0,signal(s0)
+ nor t1,zero,a0
+ and t1,t0,t1
+ beqz t1,return
+ nop
+
+ jal do_signal
+ move a1,sp # delay slot
+
+ .set noat
+ .globl return
+return: RESTORE_ALL
+ ERET
+ .set at
+ END(handle_sys)
+
+/*
+ * Beware: interrupt, fast_interrupt and bad_interrupt have unusal
+ * calling conventions!
+ *
+ * t1 - interrupt number
+ * s2 - destroyed
+ * return values:
+ * v0 - return routine
+ */
+ .text
+ .set at
+ .align 5
+ NESTED(interrupt, FR_SIZE, sp)
+ move s2,ra
+ mfc0 t0,CP0_STATUS # enable IRQs
+ ori t0,0x1f
+ xori t0,0x1e
+ mtc0 t0,CP0_STATUS
+ move a0,t1
+ jal do_IRQ
+ move a1,sp # delay slot
+ mfc0 t0,CP0_STATUS # disable IRQs
+ ori t0,1
+ xori t0,1
+ la v0,ret_from_sys_call
+ jr s2
+ mtc0 t0,CP0_STATUS # delay slot
+ END(interrupt)
+
+ .align 5
+ NESTED(fast_interrupt, FR_SIZE, sp)
+ move s2,ra
+ move a0,t1
+ jal do_fast_IRQ
+ move a1,sp # delay slot
+ lui v0,%hi(return)
+ jr s2
+ addiu v0,%lo(return) # delay slot
+ END(fast_interrupt)
+
+ LEAF(bad_interrupt)
+ /*
+ * Don't return & unblock the pic
+ */
+ j return
+ nop
+ END(bad_interrupt)
+
+ .align 5
+ LEAF(spurious_interrupt)
+ /*
+ * Nothing happened... (whistle)
+ */
+ lui t1,%hi(spurious_count)
+ lw t0,%lo(spurious_count)(t1)
+ la v0,return
+ addiu t0,1
+ jr ra
+ sw t0,%lo(spurious_count)(t1)
+ END(spurious_interrupt)
+
+
+
+/*
+ * Build a default exception handler for the other R4x00 exceptions
+ */
+#define BUILD_HANDLER(exception) \
+ .align 5; \
+ NESTED(handle_##exception, FR_SIZE, sp); \
+ .set noat; \
+ SAVE_ALL; \
+ STI; \
+ .set at; \
+ la a1,8f; \
+ TEXT (#exception); \
+ lw a2,FR_EPC(sp); \
+ PRINT("Got %s at %08x.\n"); \
+ li a0,0; \
+ li t0,-1; /* not a sys call */ \
+ sw t0,FR_ORIG_REG2(sp); \
+ jal do_##exception; \
+ move a0,sp; /* delay slot */ \
+ j ret_from_sys_call; \
+ nop; /* delay slot */ \
+ END(handle_##exception)
+
+ BUILD_HANDLER(adel)
+ BUILD_HANDLER(ades)
+ BUILD_HANDLER(ibe)
+ BUILD_HANDLER(dbe)
+ BUILD_HANDLER(ov)
+ BUILD_HANDLER(fpe)
+ BUILD_HANDLER(bp)
+ BUILD_HANDLER(tr)
+ BUILD_HANDLER(ri)
+ BUILD_HANDLER(cpu)
+ BUILD_HANDLER(vcei)
+ BUILD_HANDLER(vced)
+ BUILD_HANDLER(watch)
+ BUILD_HANDLER(reserved)
+
+
+/*
+ * Exception handler table with 32 entries.
+ * This might be extended to handle software exceptions
+ */
+ .bss
+ .align 2
+ EXPORT(exception_handlers)
+ .fill 32,4,0
+
+/*
+ * Table of syscalls
+ */
+ .data
+ EXPORT(sys_call_table)
+ PTR sys_setup /* 0 */
+ PTR sys_exit
+ PTR sys_fork
+ PTR sys_read
+ PTR sys_write
+ PTR sys_open /* 5 */
+ PTR sys_close
+ PTR sys_waitpid
+ PTR sys_creat
+ PTR sys_link
+ PTR sys_unlink /* 10 */
+ PTR sys_execve
+ PTR sys_chdir
+ PTR sys_time
+ PTR sys_mknod
+ PTR sys_chmod /* 15 */
+ PTR sys_chown
+ PTR sys_break
+ PTR sys_stat
+ PTR sys_lseek
+ PTR sys_getpid /* 20 */
+ PTR sys_mount
+ PTR sys_umount
+ PTR sys_setuid
+ PTR sys_getuid
+ PTR sys_stime /* 25 */
+ PTR sys_ptrace
+ PTR sys_alarm
+ PTR sys_fstat
+ PTR sys_pause
+ PTR sys_utime /* 30 */
+ PTR sys_stty
+ PTR sys_gtty
+ PTR sys_access
+ PTR sys_nice
+ PTR sys_ftime /* 35 */
+ PTR sys_sync
+ PTR sys_kill
+ PTR sys_rename
+ PTR sys_mkdir
+ PTR sys_rmdir /* 40 */
+ PTR sys_dup
+ PTR sys_pipe
+ PTR sys_times
+ PTR sys_prof
+ PTR sys_brk /* 45 */
+ PTR sys_setgid
+ PTR sys_getgid
+ PTR sys_signal
+ PTR sys_geteuid
+ PTR sys_getegid /* 50 */
+ PTR sys_acct
+ PTR sys_phys
+ PTR sys_lock
+ PTR sys_ioctl
+ PTR sys_fcntl /* 55 */
+ PTR sys_mpx
+ PTR sys_setpgid
+ PTR sys_ulimit
+ PTR sys_olduname
+ PTR sys_umask /* 60 */
+ PTR sys_chroot
+ PTR sys_ustat
+ PTR sys_dup2
+ PTR sys_getppid
+ PTR sys_getpgrp /* 65 */
+ PTR sys_setsid
+ PTR sys_sigaction
+ PTR sys_sgetmask
+ PTR sys_ssetmask
+ PTR sys_setreuid /* 70 */
+ PTR sys_setregid
+ PTR sys_sigsuspend
+ PTR sys_sigpending
+ PTR sys_sethostname
+ PTR sys_setrlimit /* 75 */
+ PTR sys_getrlimit
+ PTR sys_getrusage
+ PTR sys_gettimeofday
+ PTR sys_settimeofday
+ PTR sys_getgroups /* 80 */
+ PTR sys_setgroups
+ PTR sys_select
+ PTR sys_symlink
+ PTR sys_lstat
+ PTR sys_readlink /* 85 */
+ PTR sys_uselib
+ PTR sys_swapon
+ PTR sys_reboot
+ PTR old_readdir
+ PTR sys_mmap /* 90 */
+ PTR sys_munmap
+ PTR sys_truncate
+ PTR sys_ftruncate
+ PTR sys_fchmod
+ PTR sys_fchown /* 95 */
+ PTR sys_getpriority
+ PTR sys_setpriority
+ PTR sys_profil
+ PTR sys_statfs
+ PTR sys_fstatfs /* 100 */
+ PTR sys_ioperm
+ PTR sys_socketcall
+ PTR sys_syslog
+ PTR sys_setitimer
+ PTR sys_getitimer /* 105 */
+ PTR sys_newstat
+ PTR sys_newlstat
+ PTR sys_newfstat
+ PTR sys_uname
+ PTR sys_iopl /* 110 */
+ PTR sys_vhangup
+ PTR sys_idle
+ PTR sys_vm86
+ PTR sys_wait4
+ PTR sys_swapoff /* 115 */
+ PTR sys_sysinfo
+ PTR sys_ipc
+ PTR sys_fsync
+ PTR sys_sigreturn
+ PTR sys_clone /* 120 */
+ PTR sys_setdomainname
+ PTR sys_newuname
+ PTR 0 #sys_modify_ldt
+ PTR sys_adjtimex
+ PTR sys_mprotect /* 125 */
+ PTR sys_sigprocmask
+ PTR sys_create_module
+ PTR sys_init_module
+ PTR sys_delete_module
+ PTR sys_get_kernel_syms /* 130 */
+ PTR sys_quotactl
+ PTR sys_getpgid
+ PTR sys_fchdir
+ PTR sys_bdflush
+ PTR sys_sysfs /* 135 */
+ PTR sys_personality
+ PTR 0 /* for afs_syscall */
+ PTR sys_setfsuid
+ PTR sys_setfsgid
+ PTR sys_llseek /* 140 */
+ PTR sys_getdents
+ PTR sys_select
+ PTR sys_flock
+ .space (NR_syscalls-140)*4
+
+ .bss
+ EXPORT(IRQ_vectors)
+ .fill 16,4,0
+
+ .text
+sys_call_names:
+ TTABLE ("setup")
+ TTABLE ("exit")
+ TTABLE ("fork")
+ TTABLE ("read")
+ TTABLE ("write")
+ TTABLE ("open")
+ TTABLE ("close")
+ TTABLE ("waitpid")
+ TTABLE ("creat")
+ TTABLE ("link")
+ TTABLE ("unlink")
+ TTABLE ("execve")
+ TTABLE ("chdir")
+ TTABLE ("time")
+ TTABLE ("mknod")
+ TTABLE ("chmod")
+ TTABLE ("chown")
+ TTABLE ("break")
+ TTABLE ("stat")
+ TTABLE ("lseek")
+ TTABLE ("getpid")
+ TTABLE ("mount")
+ TTABLE ("umount")
+ TTABLE ("setuid")
+ TTABLE ("getuid")
+ TTABLE ("stime")
+ TTABLE ("ptrace")
+ TTABLE ("alarm")
+ TTABLE ("fstat")
+ TTABLE ("pause")
+ TTABLE ("utime")
+ TTABLE ("stty")
+ TTABLE ("gtty")
+ TTABLE ("access")
+ TTABLE ("nice")
+ TTABLE ("ftime")
+ TTABLE ("sync")
+ TTABLE ("kill")
+ TTABLE ("rename")
+ TTABLE ("mkdir")
+ TTABLE ("rmdir")
+ TTABLE ("dup")
+ TTABLE ("pipe")
+ TTABLE ("times")
+ TTABLE ("prof")
+ TTABLE ("brk")
+ TTABLE ("setgid")
+ TTABLE ("getgid")
+ TTABLE ("signal")
+ TTABLE ("geteuid")
+ TTABLE ("getegid")
+ TTABLE ("acct")
+ TTABLE ("phys")
+ TTABLE ("lock")
+ TTABLE ("ioctl")
+ TTABLE ("fcntl")
+ TTABLE ("mpx")
+ TTABLE ("setpgid")
+ TTABLE ("ulimit")
+ TTABLE ("olduname")
+ TTABLE ("umask")
+ TTABLE ("chroot")
+ TTABLE ("ustat")
+ TTABLE ("dup2")
+ TTABLE ("getppid")
+ TTABLE ("getpgrp")
+ TTABLE ("setsid")
+ TTABLE ("sigaction")
+ TTABLE ("sgetmask")
+ TTABLE ("ssetmask")
+ TTABLE ("setreuid")
+ TTABLE ("setregid")
+ TTABLE ("sigsuspend")
+ TTABLE ("sigpending")
+ TTABLE ("sethostname")
+ TTABLE ("setrlimit")
+ TTABLE ("getrlimit")
+ TTABLE ("getrusage")
+ TTABLE ("gettimeofday")
+ TTABLE ("settimeofday")
+ TTABLE ("getgroups")
+ TTABLE ("setgroups")
+ TTABLE ("select")
+ TTABLE ("symlink")
+ TTABLE ("lstat")
+ TTABLE ("readlink")
+ TTABLE ("uselib")
+ TTABLE ("swapon")
+ TTABLE ("reboot")
+ TTABLE ("readdir")
+ TTABLE ("mmap")
+ TTABLE ("munmap")
+ TTABLE ("truncate")
+ TTABLE ("ftruncate")
+ TTABLE ("fchmod")
+ TTABLE ("fchown")
+ TTABLE ("getpriority")
+ TTABLE ("setpriority")
+ TTABLE ("profil")
+ TTABLE ("statfs")
+ TTABLE ("fstatfs")
+ TTABLE ("ioperm")
+ TTABLE ("socketcall")
+ TTABLE ("syslog")
+ TTABLE ("setitimer")
+ TTABLE ("getitimer")
+ TTABLE ("newstat")
+ TTABLE ("newlstat")
+ TTABLE ("newfstat")
+ TTABLE ("uname")
+ TTABLE ("iopl")
+ TTABLE ("vhangup")
+ TTABLE ("idle")
+ TTABLE ("vm86")
+ TTABLE ("wait4")
+ TTABLE ("swapoff")
+ TTABLE ("sysinfo")
+ TTABLE ("ipc")
+ TTABLE ("fsync")
+ TTABLE ("sigreturn")
+ TTABLE ("clone")
+ TTABLE ("setdomainname")
+ TTABLE ("newuname")
+ TTABLE ("modify_ldt (unused)")
+ TTABLE ("adjtimex")
+ TTABLE ("mprotect")
+ TTABLE ("sigprocmask")
+ TTABLE ("create_module")
+ TTABLE ("init_module")
+ TTABLE ("delete_module")
+ TTABLE ("get_kernel_syms")
+ TTABLE ("quotactl")
+ TTABLE ("getpgid")
+ TTABLE ("fchdir")
+ TTABLE ("bdflush")
+ TTABLE ("sysfs")
+ TTABLE ("personality")
+ TTABLE ("afs_syscall") /* for afs_syscall */
+ TTABLE ("setfsuid")
+ TTABLE ("setfsgid")
+ TTABLE ("llseek")
+ TTABLE ("sys_getdents")
+ TTABLE ("sys_select")
+ TTABLE ("sys_flock")
diff --git a/arch/mips/kernel/gdb-low.S b/arch/mips/kernel/gdb-low.S
new file mode 100644
index 000000000..ea775e732
--- /dev/null
+++ b/arch/mips/kernel/gdb-low.S
@@ -0,0 +1,300 @@
+/*
+ * arch/mips/kernel/gdb-low.S
+ *
+ * gdb-low.S contains the low-level trap handler for the GDB stub.
+ *
+ * Copyright (C) 1995 Andreas Busse
+ */
+
+#include <linux/sys.h>
+
+#include <asm/asm.h>
+#include <asm/segment.h>
+#include <asm/mipsregs.h>
+#include <asm/mipsconfig.h>
+#include <asm/stackframe.h>
+#include <asm/gdb-stub.h>
+
+/*
+ * 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, new stack
+ */
+ lui k1,%hi(kernelsp)
+ lw k1,%lo(kernelsp)(k1)
+1: move k0,sp
+ subu sp,k1,GDB_FR_SIZE
+ sw k0,GDB_FR_REG29(sp)
+ sw v0,GDB_FR_REG2(sp)
+
+/*
+ * first save the CP0 and special registers
+ */
+
+ mfc0 v0,CP0_STATUS
+ sw v0,GDB_FR_STATUS(sp)
+ mfc0 v0,CP0_CAUSE
+ sw v0,GDB_FR_CAUSE(sp)
+ mfc0 v0,CP0_EPC
+ sw v0,GDB_FR_EPC(sp)
+ mfc0 v0,CP0_BADVADDR
+ sw v0,GDB_FR_BADVADDR(sp)
+ mfhi v0
+ sw v0,GDB_FR_HI(sp)
+ mflo v0
+ sw v0,GDB_FR_LO(sp)
+
+/*
+ * Now the integer registers
+ */
+
+ sw zero,GDB_FR_REG0(sp) /* I know... */
+ sw $1,GDB_FR_REG1(sp)
+ /* v0 already saved */
+ sw v1,GDB_FR_REG3(sp)
+ sw a0,GDB_FR_REG4(sp)
+ sw a1,GDB_FR_REG5(sp)
+ sw a2,GDB_FR_REG6(sp)
+ sw a3,GDB_FR_REG7(sp)
+ sw t0,GDB_FR_REG8(sp)
+ sw t1,GDB_FR_REG9(sp)
+ sw t2,GDB_FR_REG10(sp)
+ sw t3,GDB_FR_REG11(sp)
+ sw t4,GDB_FR_REG12(sp)
+ sw t5,GDB_FR_REG13(sp)
+ sw t6,GDB_FR_REG14(sp)
+ sw t7,GDB_FR_REG15(sp)
+ sw s0,GDB_FR_REG16(sp)
+ sw s1,GDB_FR_REG17(sp)
+ sw s2,GDB_FR_REG18(sp)
+ sw s3,GDB_FR_REG19(sp)
+ sw s4,GDB_FR_REG20(sp)
+ sw s5,GDB_FR_REG21(sp)
+ sw s6,GDB_FR_REG22(sp)
+ sw s7,GDB_FR_REG23(sp)
+ sw t8,GDB_FR_REG24(sp)
+ sw t9,GDB_FR_REG25(sp)
+ sw k0,GDB_FR_REG26(sp)
+ sw k1,GDB_FR_REG27(sp)
+ sw gp,GDB_FR_REG28(sp)
+ /* sp already saved */
+ sw fp,GDB_FR_REG30(sp)
+ sw ra,GDB_FR_REG31(sp)
+
+ STI /* disable interrupts */
+
+/*
+ * Followed by 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,2f /* disabled, skip */
+ nop
+
+ swc1 $0,GDB_FR_FPR0(sp)
+ swc1 $1,GDB_FR_FPR1(sp)
+ swc1 $2,GDB_FR_FPR2(sp)
+ swc1 $3,GDB_FR_FPR3(sp)
+ swc1 $4,GDB_FR_FPR4(sp)
+ swc1 $5,GDB_FR_FPR5(sp)
+ swc1 $6,GDB_FR_FPR6(sp)
+ swc1 $7,GDB_FR_FPR7(sp)
+ swc1 $8,GDB_FR_FPR8(sp)
+ swc1 $9,GDB_FR_FPR9(sp)
+ swc1 $10,GDB_FR_FPR10(sp)
+ swc1 $11,GDB_FR_FPR11(sp)
+ swc1 $12,GDB_FR_FPR12(sp)
+ swc1 $13,GDB_FR_FPR13(sp)
+ swc1 $14,GDB_FR_FPR14(sp)
+ swc1 $15,GDB_FR_FPR15(sp)
+ swc1 $16,GDB_FR_FPR16(sp)
+ swc1 $17,GDB_FR_FPR17(sp)
+ swc1 $18,GDB_FR_FPR18(sp)
+ swc1 $19,GDB_FR_FPR19(sp)
+ swc1 $20,GDB_FR_FPR20(sp)
+ swc1 $21,GDB_FR_FPR21(sp)
+ swc1 $22,GDB_FR_FPR22(sp)
+ swc1 $23,GDB_FR_FPR23(sp)
+ swc1 $24,GDB_FR_FPR24(sp)
+ swc1 $25,GDB_FR_FPR25(sp)
+ swc1 $26,GDB_FR_FPR26(sp)
+ swc1 $27,GDB_FR_FPR27(sp)
+ swc1 $28,GDB_FR_FPR28(sp)
+ swc1 $29,GDB_FR_FPR29(sp)
+ swc1 $30,GDB_FR_FPR30(sp)
+ swc1 $31,GDB_FR_FPR31(sp)
+
+/*
+ * FPU control registers
+ */
+
+ mfc1 v0,CP1_STATUS
+ sw v0,GDB_FR_FSR(sp)
+ mfc1 v0,CP1_REVISION
+ sw v0,GDB_FR_FIR(sp)
+
+/*
+ * current stack frame ptr
+ */
+
+2: sw sp,GDB_FR_FRP(sp)
+
+/*
+ * CP0 registers (R4000/R4400 unused registers skipped)
+ */
+
+ mfc0 v0,CP0_INDEX
+ sw v0,GDB_FR_CP0_INDEX(sp)
+ mfc0 v0,CP0_RANDOM
+ sw v0,GDB_FR_CP0_RANDOM(sp)
+ mfc0 v0,CP0_ENTRYLO0
+ sw v0,GDB_FR_CP0_ENTRYLO0(sp)
+ mfc0 v0,CP0_ENTRYLO1
+ sw v0,GDB_FR_CP0_ENTRYLO1(sp)
+ mfc0 v0,CP0_PAGEMASK
+ sw v0,GDB_FR_CP0_PAGEMASK(sp)
+ mfc0 v0,CP0_WIRED
+ sw v0,GDB_FR_CP0_WIRED(sp)
+ mfc0 v0,CP0_ENTRYHI
+ sw v0,GDB_FR_CP0_ENTRYHI(sp)
+ mfc0 v0,CP0_PRID
+ sw 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
+
+ lw v0,GDB_FR_CP0_ENTRYHI(sp)
+ lw v1,GDB_FR_CP0_WIRED(sp)
+ mtc0 v0,CP0_ENTRYHI
+ mtc0 v1,CP0_WIRED
+ lw v0,GDB_FR_CP0_PAGEMASK(sp)
+ lw v1,GDB_FR_CP0_ENTRYLO1(sp)
+ mtc0 v0,CP0_PAGEMASK
+ mtc0 v1,CP0_ENTRYLO1
+ lw v0,GDB_FR_CP0_ENTRYLO0(sp)
+ lw v1,GDB_FR_CP0_INDEX(sp)
+ mtc0 v0,CP0_ENTRYLO0
+ mtc0 v1,CP0_INDEX
+
+/*
+ * 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
+
+ lwc1 $31,GDB_FR_FPR31(sp)
+ lwc1 $30,GDB_FR_FPR30(sp)
+ lwc1 $29,GDB_FR_FPR29(sp)
+ lwc1 $28,GDB_FR_FPR28(sp)
+ lwc1 $27,GDB_FR_FPR27(sp)
+ lwc1 $26,GDB_FR_FPR26(sp)
+ lwc1 $25,GDB_FR_FPR25(sp)
+ lwc1 $24,GDB_FR_FPR24(sp)
+ lwc1 $23,GDB_FR_FPR23(sp)
+ lwc1 $22,GDB_FR_FPR22(sp)
+ lwc1 $21,GDB_FR_FPR21(sp)
+ lwc1 $20,GDB_FR_FPR20(sp)
+ lwc1 $19,GDB_FR_FPR19(sp)
+ lwc1 $18,GDB_FR_FPR18(sp)
+ lwc1 $17,GDB_FR_FPR17(sp)
+ lwc1 $16,GDB_FR_FPR16(sp)
+ lwc1 $15,GDB_FR_FPR15(sp)
+ lwc1 $14,GDB_FR_FPR14(sp)
+ lwc1 $13,GDB_FR_FPR13(sp)
+ lwc1 $12,GDB_FR_FPR12(sp)
+ lwc1 $11,GDB_FR_FPR11(sp)
+ lwc1 $10,GDB_FR_FPR10(sp)
+ lwc1 $9,GDB_FR_FPR9(sp)
+ lwc1 $8,GDB_FR_FPR8(sp)
+ lwc1 $7,GDB_FR_FPR7(sp)
+ lwc1 $6,GDB_FR_FPR6(sp)
+ lwc1 $5,GDB_FR_FPR5(sp)
+ lwc1 $4,GDB_FR_FPR4(sp)
+ lwc1 $3,GDB_FR_FPR3(sp)
+ lwc1 $2,GDB_FR_FPR2(sp)
+ lwc1 $1,GDB_FR_FPR1(sp)
+ lwc1 $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
+
+ lw v0,GDB_FR_STATUS(sp)
+ lw v1,GDB_FR_EPC(sp)
+ mtc0 v0,CP0_STATUS
+ mtc0 v1,CP0_EPC
+ lw v0,GDB_FR_HI(sp)
+ lw v1,GDB_FR_LO(sp)
+ mthi v0
+ mtlo v0
+ lw ra,GDB_FR_REG31(sp)
+ lw fp,GDB_FR_REG30(sp)
+ lw gp,GDB_FR_REG28(sp)
+ lw k1,GDB_FR_REG27(sp)
+ lw k0,GDB_FR_REG26(sp)
+ lw t9,GDB_FR_REG25(sp)
+ lw t8,GDB_FR_REG24(sp)
+ lw s7,GDB_FR_REG23(sp)
+ lw s6,GDB_FR_REG22(sp)
+ lw s5,GDB_FR_REG21(sp)
+ lw s4,GDB_FR_REG20(sp)
+ lw s3,GDB_FR_REG19(sp)
+ lw s2,GDB_FR_REG18(sp)
+ lw s1,GDB_FR_REG17(sp)
+ lw s0,GDB_FR_REG16(sp)
+ lw t7,GDB_FR_REG15(sp)
+ lw t6,GDB_FR_REG14(sp)
+ lw t5,GDB_FR_REG13(sp)
+ lw t4,GDB_FR_REG12(sp)
+ lw t3,GDB_FR_REG11(sp)
+ lw t2,GDB_FR_REG10(sp)
+ lw t1,GDB_FR_REG9(sp)
+ lw t0,GDB_FR_REG8(sp)
+ lw a3,GDB_FR_REG7(sp)
+ lw a2,GDB_FR_REG6(sp)
+ lw a1,GDB_FR_REG5(sp)
+ lw a0,GDB_FR_REG4(sp)
+ lw v1,GDB_FR_REG3(sp)
+ lw v0,GDB_FR_REG2(sp)
+ lw $1,GDB_FR_REG1(sp)
+ lw sp,GDB_FR_REG29(sp) /* Deallocate stack */
+
+ ERET
+ .set at
+ .set reorder
+ END(trap_low)
+
+/* end of file gdb-low.S */
diff --git a/arch/mips/kernel/gdb-stub.c b/arch/mips/kernel/gdb-stub.c
new file mode 100644
index 000000000..7708feac0
--- /dev/null
+++ b/arch/mips/kernel/gdb-stub.c
@@ -0,0 +1,748 @@
+/*
+ * 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
+ */
+
+/*
+ * 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
+ *
+ */
+
+#include <linux/string.h>
+#include <linux/signal.h>
+#include <linux/kernel.h>
+
+#include <asm/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/segment.h>
+#include <asm/cachectl.h>
+#include <asm/system.h>
+#include <asm/gdb-stub.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 fltr_set_mem_err(void);
+extern void trap_low(void);
+
+/*
+ * breakpoint and test functions
+ */
+extern void breakpoint(void);
+extern void breakinst(void);
+extern void adel(void);
+
+/*
+ * local prototypes
+ */
+
+static void getpacket(char *buffer);
+static void putpacket(char *buffer);
+static void set_mem_fault_trap(int enable);
+static int computeSignal(int tt);
+static int hex(unsigned char ch);
+static int hexToInt(char **ptr, int *intValue);
+static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault);
+void handle_exception(struct gdb_regs *regs);
+static void show_gdbregs(struct gdb_regs *regs);
+
+/*
+ * 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; /* !0 means we've been initialized */
+static const char hexchars[]="0123456789abcdef";
+
+
+/*
+ * 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() & 0x7f;
+ 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) != '+');
+}
+
+
+/*
+ * Indicate to caller of mem2hex or hex2mem that there
+ * has been an error.
+ */
+static volatile int mem_err = 0;
+
+/*
+ * 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.
+ * If MAY_FAULT is non-zero, then we will handle memory faults by returning
+ * a 0, else treat a fault like any other fault in the stub.
+ */
+static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault)
+{
+ unsigned char ch;
+
+/* set_mem_fault_trap(may_fault); */
+
+ while (count-- > 0) {
+ ch = *(mem++);
+ if (mem_err)
+ return 0;
+ *buf++ = hexchars[ch >> 4];
+ *buf++ = hexchars[ch & 0xf];
+ }
+
+ *buf = 0;
+
+/* set_mem_fault_trap(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
+ */
+static char *hex2mem(char *buf, char *mem, int count, int may_fault)
+{
+ int i;
+ unsigned char ch;
+
+/* set_mem_fault_trap(may_fault); */
+
+ for (i=0; i<count; i++)
+ {
+ ch = hex(*buf++) << 4;
+ ch |= hex(*buf++);
+ *(mem++) = ch;
+ if (mem_err)
+ return 0;
+ }
+
+/* set_mem_fault_trap(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[] = {
+ { 4, SIGBUS }, /* address error (load) */
+ { 5, SIGBUS }, /* address error (store) */
+ { 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 */
+};
+
+
+/*
+ * Set up exception handlers for tracing and breakpoints
+ */
+void set_debug_traps(void)
+{
+ struct hard_trap_info *ht;
+
+ for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
+ set_except_vector(ht->tt, trap_low);
+
+ /*
+ * In case GDB is started before us, ack any packets
+ * (presumably "$?#xx") sitting there.
+ */
+
+ putDebugChar ('+');
+ initialized = 1;
+
+ breakpoint();
+}
+
+
+/*
+ * Trap handler for memory errors. This just sets mem_err to be non-zero. It
+ * assumes that %l1 is non-zero. This should be safe, as it is doubtful that
+ * 0 would ever contain code that could mem fault. This routine will skip
+ * past the faulting instruction after setting mem_err.
+ */
+extern void fltr_set_mem_err(void)
+{
+ /* FIXME: Needs to be written... */
+}
+
+
+static void set_mem_fault_trap(int enable)
+{
+ mem_err = 0;
+
+#if 0
+ if (enable)
+ exceptionHandler(9, fltr_set_mem_err);
+ else
+ exceptionHandler(9, trap_low);
+#endif
+}
+
+/*
+ * 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);
+}
+
+/*
+ * This function does all command procesing 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;
+ int addr;
+ int length;
+ char *ptr;
+ unsigned long *stack;
+
+#if 0
+ printk("in handle_exception()\n");
+ show_gdbregs(regs);
+#endif
+
+ /*
+ * First check trap type. If this is CPU_UNUSABLE and CPU_ID is 1,
+ * the simply switch the FPU on and return since this is no error
+ * condition. kernel/traps.c does the same.
+ * FIXME: This doesn't work yet, so we don't catch CPU_UNUSABLE
+ * traps for now.
+ */
+ trap = (regs->cp0_cause & 0x7c) >> 2;
+/* printk("trap=%d\n",trap); */
+ if (trap == 11) {
+ if (((regs->cp0_cause >> CAUSEB_CE) & 3) == 1) {
+ regs->cp0_status |= ST0_CU1;
+ return;
+ }
+ }
+
+ /*
+ * If we're in breakpoint() increment the PC
+ */
+ if (trap == 9 && regs->cp0_epc == (unsigned long)breakinst)
+ regs->cp0_epc += 4;
+
+ 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, 4, 0);
+ *ptr++ = ';';
+
+ /*
+ * Send frame pointer
+ */
+ *ptr++ = hexchars[REG_FP >> 4];
+ *ptr++ = hexchars[REG_FP & 0xf];
+ *ptr++ = ':';
+ ptr = mem2hex((char *)&regs->reg30, ptr, 4, 0);
+ *ptr++ = ';';
+
+ /*
+ * Send stack pointer
+ */
+ *ptr++ = hexchars[REG_SP >> 4];
+ *ptr++ = hexchars[REG_SP & 0xf];
+ *ptr++ = ':';
+ ptr = mem2hex((char *)&regs->reg29, ptr, 4, 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;
+
+ 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*4, 0); /* r0...r31 */
+ ptr = mem2hex((char *)&regs->cp0_status, ptr, 6*4, 0); /* cp0 */
+ ptr = mem2hex((char *)&regs->fpr0, ptr, 32*4, 0); /* f0...31 */
+ ptr = mem2hex((char *)&regs->cp1_fsr, ptr, 2*4, 0); /* cp1 */
+ ptr = mem2hex((char *)&regs->frame_ptr, ptr, 2*4, 0); /* frp */
+ ptr = mem2hex((char *)&regs->cp0_index, ptr, 16*4, 0); /* cp0 */
+ break;
+
+ /*
+ * set the value of the CPU registers - return OK
+ * FIXME: Needs to be written
+ */
+ case 'G':
+ {
+#if 0
+ unsigned long *newsp, psr;
+
+ ptr = &input_buffer[1];
+ hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */
+
+ /*
+ * See if the stack pointer has moved. If so, then copy the
+ * saved locals and ins to the new location.
+ */
+
+ newsp = (unsigned long *)registers[SP];
+ if (sp != newsp)
+ sp = memcpy(newsp, sp, 16 * 4);
+
+#endif
+ strcpy(output_buffer,"OK");
+ }
+ break;
+
+ /*
+ * mAA..AA,LLLL Read LLLL bytes at address AA..AA
+ */
+ case 'm':
+ ptr = &input_buffer[1];
+
+ if (hexToInt(&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;
+
+ /*
+ * MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK
+ */
+ case 'M':
+ ptr = &input_buffer[1];
+
+ if (hexToInt(&ptr, &addr)
+ && *ptr++ == ','
+ && hexToInt(&ptr, &length)
+ && *ptr++ == ':') {
+ if (hex2mem(ptr, (char *)addr, length, 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 (hexToInt(&ptr, &addr))
+ regs->cp0_epc = addr;
+
+ /*
+ * Need to flush the instruction cache here, as we may
+ * have deposited a breakpoint, and the icache probably
+ * has no way of knowing that a data ref to some location
+ * may have changed something that is in the instruction
+ * cache.
+ * NB: We flush both caches, just to be sure...
+ */
+
+ sys_cacheflush((void *)KSEG0,KSEG1-KSEG0,BCACHE);
+ return;
+ /* NOTREACHED */
+ break;
+
+
+ /*
+ * kill the program
+ */
+ case 'k' :
+ break; /* do nothing */
+
+
+ /*
+ * Reset the whole machine (FIXME: system dependent)
+ */
+ case 'r':
+ break;
+
+
+ /*
+ * Step to next instruction
+ * FIXME: Needs to be written
+ */
+ case 's':
+ strcpy (output_buffer, "S01");
+ 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 */
+}
+
+/*
+ * 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
+ .set noreorder
+ nop
+breakinst: break
+ nop
+ .set reorder
+ ");
+}
+
+void adel(void)
+{
+ __asm__ __volatile__("
+ .globl adel
+ la $8,0x80000001
+ lw $9,0($8)
+ ");
+}
+
+/*
+ * 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);
+}
diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
new file mode 100644
index 000000000..a2cb43de3
--- /dev/null
+++ b/arch/mips/kernel/head.S
@@ -0,0 +1,412 @@
+/*
+ * arch/mips/kernel/head.S
+ *
+ * Copyright (C) 1994, 1995 Waldorf Electronics
+ * Written by Ralf Baechle and Andreas Busse
+ *
+ * Head.S contains the MIPS exception handler and startup code.
+ */
+#include <linux/tasks.h>
+
+#include <asm/asm.h>
+#include <asm/segment.h>
+#include <asm/cachectl.h>
+#include <asm/mipsregs.h>
+#include <asm/mipsconfig.h>
+#include <asm/stackframe.h>
+#include <asm/bootinfo.h>
+
+#define PAGE_SIZE 0x1000
+
+#define MODE_GLOBAL 0x0001 /* shared for all processes */
+#define MODE_ALIAS 0x0016 /* uncachable */
+
+ .text
+ .set mips3
+/*
+ * This is space for the interrupt handlers.
+ * They are located at virtual address KSEG[01] (physical 0x0)
+ */
+ /*
+ * TLB refill, EXL == 0
+ */
+ .set noreorder
+ .set noat
+ LEAF(except_vec0)
+ dmfc0 k1,CP0_CONTEXT
+ dsra k1,1
+ lwu k0,(k1) # May cause another exception
+ lwu k1,4(k1)
+ dsrl k0,6 # Convert to EntryLo format
+ dsrl k1,6 # Convert to EntryLo format
+ dmtc0 k0,CP0_ENTRYLO0
+ dmtc0 k1,CP0_ENTRYLO1
+ nop # Needed for R4[04]00 pipeline
+ tlbwr
+ nop # Needed for R4[04]00 pipeline
+ nop
+ nop
+ eret
+ /*
+ * Workaround for R4000 bug. For explanation see MIPS
+ * docs. Note that this that obscure that it wont almost
+ * never happen. Well, but Mips writes about it's bugs.
+ */
+ nop
+ eret
+ END(except_vec0)
+
+ /*
+ * XTLB refill, EXL == 0
+ * Should never be reached
+ */
+ .org except_vec0+0x80
+ LEAF(except_vec1)
+ PANIC("XTLB Refill exception.\n")
+1: j 1b
+ nop
+ END(except_vec1)
+
+ /*
+ * Cache Error
+ */
+ .org except_vec1+0x80
+ LEAF(except_vec2)
+ /*
+ * Famous last words: unreached
+ */
+ mfc0 a1,CP0_ERROREPC
+ PRINT("Cache error exception: c0_errorepc == %08x\n")
+1: j 1b
+ nop
+ END(except_vec2)
+
+ /*
+ * General exception vector.
+ */
+ .org except_vec2+0x80
+ NESTED(except_vec3, 0, sp)
+ .set noat
+ /*
+ * Register saving is delayed as long as we don't know
+ * which registers really need to be saved.
+ */
+ mfc0 k1,CP0_CAUSE
+ la k0,exception_handlers
+ /*
+ * Next lines assumes that the used CPU type has max.
+ * 32 different types of exceptions. We might use this
+ * to implement software exceptions in the future.
+ */
+ andi k1,0x7c
+ addu k0,k1
+ lw k0,(k0)
+ NOP
+ jr k0
+ nop
+ END(except_vec3)
+ .set at
+
+/******************************************************************************/
+
+/*
+ * Kernel entry
+ */
+ .set noreorder
+ NESTED(kernel_entry, 16, sp)
+ /*
+ * Clear BSS first so that there are no surprises...
+ */
+ la t0,_edata
+ la t1,_end
+ sw zero,(t0)
+1: addiu t0,4
+ bnel t0,t1,1b
+ sw zero,(t0)
+
+ /*
+ * Initialize low level part of memory management
+ */
+ jal tlbflush
+ mtc0 zero,CP0_WIRED # delay slot
+ jal wire_mappings
+ nop
+ jal tlbflush
+ nop
+
+ /*
+ * Stack for kernel and init
+ */
+ la sp,init_user_stack+PAGE_SIZE-24
+ la t0,init_kernel_stack+PAGE_SIZE
+ sw t0,kernelsp
+
+ /*
+ * Disable coprocessors
+ */
+ mfc0 t0,CP0_STATUS
+ li t1,~(ST0_CU0|ST0_CU1|ST0_CU2|ST0_CU3)
+ and t0,t1
+ mtc0 t0,CP0_STATUS
+
+1: jal start_kernel
+ nop # delay slot
+ /*
+ * Main should never return here, but
+ * just in case, we know what happens.
+ */
+ b 1b
+ nop # delay slot
+ END(kernel_entry)
+
+/*
+ * wire_mappings - used to map hardware registers
+ */
+ LEAF(wire_mappings)
+ /*
+ * Get base address of map0 table for the
+ * the board we're running on
+ */
+ la t0,boot_info
+ lw t1,OFFSET_BOOTINFO_MACHTYPE(t0)
+ la t0,map0table
+ sll t1,PTRLOG # machtype used as index
+ addu t0,t1
+ lw t0,(t0) # get base address
+
+ /*
+ * Get number of wired TLB entries and
+ * loop over selected map0 table.
+ */
+ lw t1,(t0) # number of wired TLB entries
+ move t2,zero # TLB entry counter
+ addiu t3,t1,1 # wire one additional entry
+ beqz t1,2f # null, exit
+ mtc0 t3,CP0_WIRED # delay slot
+ addiu t0,8
+1: lw t4,24(t0) # PageMask
+ ld t5,0(t0) # entryHi
+ ld t6,8(t0) # entryLo0
+ ld t7,16(t0) # entryLo1
+ addiu t2,1 # increment ctr
+ mtc0 t2,CP0_INDEX # set TLB entry
+ mtc0 t4,CP0_PAGEMASK
+ dmtc0 t5,CP0_ENTRYHI
+ dmtc0 t6,CP0_ENTRYLO0
+ dmtc0 t7,CP0_ENTRYLO1
+ addiu t0,32
+ bne t1,t2,1b # next TLB entry
+ tlbwi # delay slot
+
+ /*
+ * We use only 4k pages. Therefore the PageMask register
+ * is expected to be setup for 4k pages.
+ */
+2: li t0,PM_4K
+ mtc0 t0,CP0_PAGEMASK
+
+ /*
+ * Now map the pagetables
+ */
+ mtc0 zero,CP0_INDEX
+ la t0,TLB_ROOT
+ dmtc0 t0,CP0_ENTRYHI
+ la t0,swapper_pg_dir-KSEG1
+ srl t0,6
+ ori t0,(MODE_ALIAS|MODE_GLOBAL) # uncachable, dirty, valid
+ dmtc0 t0,CP0_ENTRYLO0
+ li t0,MODE_GLOBAL
+ dmtc0 t0,CP0_ENTRYLO1
+ nop
+ tlbwi # delayed
+
+ /*
+ * Load the context register with a value that allows
+ * it to be used as fast as possible in tlb exceptions.
+ * It is expected that this register's content will
+ * NEVER be changed.
+ */
+ li t0,TLBMAP
+ dsll t0,1
+ dmtc0 t0,CP0_CONTEXT
+ jr ra # delay slot
+ nop
+ END(wire_mappings)
+
+/*
+ * Just for debugging...
+ */
+ .set noreorder
+ LEAF(beep)
+ lw t0,beepflag
+ nop
+ bnez t0,1f
+ lbu t0,0xe2000061
+ xori t0,3
+ sb t0,0xe2000061
+ li t0,1
+ sw t0,beepflag
+1: jr ra
+ nop
+ END(beep)
+
+ .bss
+beepflag: .word 0
+ .text
+
+/*
+ * Compute kernel code checksum to check kernel code against corruption
+ */
+ LEAF(csum)
+ jal sys_cacheflush
+ move t8,ra # delay slot
+ li t0,KSEG1
+ la t1,final
+ li t2,KSEG1
+ or t0,t2
+ or t1,t2
+ move v0,zero
+1: lw t2,(t0)
+ addiu t0,4
+ bne t0,t1,1b
+ xor v0,t2
+ jr t8
+ nop
+ END(csum)
+final:
+
+ .data
+/*
+ * Build an entry for table of wired entries
+ */
+#define MAPDATA(q1,q2,q3,w1) \
+ .quad q1; \
+ .quad q2; \
+ .quad q3; \
+ .word w1; \
+ .word 0
+
+/*
+ * Initial mapping tables for supported Mips boards.
+ * First item is always the number of wired TLB entries,
+ * following by EntryHi/EntryLo pairs and page mask.
+ * Since everything must be quad-aligned (8) we insert
+ * some dummy zeros.
+ */
+
+/*
+ * Address table of mapping tables for supported Mips boards.
+ * Add your own stuff here but don't forget to define your
+ * target system in bootinfo.h
+ */
+
+map0table: PTR map0_dummy # machtype = unknown
+ PTR map0_rpc # Deskstation rPC44
+ PTR map0_tyne # Deskstation Tyne
+ PTR map0_pica61 # Acer Pica-61
+ PTR map0_magnum4000 # MIPS Magnum 4000PC (RC4030)
+
+map0_dummy: .word 0 # 0 entries
+
+ .align 3
+/*
+ * Initial mappings for Deskstation rPC boards.
+ * RB: Untested goodie - I don't have such a board.
+ */
+map0_rpc: .word 2 # no. of wired TLB entries
+ .word 0 # pad for alignment
+
+MAPDATA(0xffffffffe0000000, 0x04020017, 0x00000001, PM_1M) # VESA DMA cache
+MAPDATA(0xffffffffe2000000, 0x24000017, 0x04000017, PM_16M) # VESA I/O and memory space
+
+/*
+ * Initial mappings for Deskstation Tyne boards.
+ */
+map0_tyne: .word 2 # no. of wired TLB entries
+ .word 0 # pad for alignment
+
+MAPDATA(0xffffffffe0000000, 0x04020017, 0x00000001, PM_1M) # VESA DMA cache
+MAPDATA(0xffffffffe2000000, 0x24000017, 0x04000017, PM_16M) # VESA I/O and memory space
+
+/*
+ * Initial mapping for ACER PICA-61 boards.
+ * FIXME: These are rather preliminary since many drivers, such as serial,
+ * parallel, scsi and ethernet need some changes to distinguish between "local"
+ * (built-in) and "optional" (ISA/PCI) I/O hardware. Local video ram is mapped
+ * to the same location as the bios maps it to. Console driver has been changed
+ * accordingly (new video type: VIDEO_TYPE_PICA_S3).
+ * FIXME: Remove or merge some of the mappings.
+ */
+map0_pica61: .word 7 # no. wired TLB entries
+ .word 0 # dummy
+
+MAPDATA(0xffffffffe0000000, 0x02000017, 0x00000001, PM_64K) # Local I/O space
+MAPDATA(0xffffffffe0100000, 0x03c00017, 0x00000001, PM_4K) # Interrupt source register
+MAPDATA(0xffffffffe0200000, 0x01800017, 0x01804017, PM_1M) # Local video control
+MAPDATA(0xffffffffe0400000, 0x01808017, 0x0180c017, PM_1M) # Extended video control
+MAPDATA(0xffffffffe0800000, 0x01000017, 0x01010017, PM_4M) # Local video memory (BIOS mapping)
+MAPDATA(0xffffffffe2000000, 0x02400017, 0x02440017, PM_16M) # ISA I/O and ISA memory space (both 16M)
+MAPDATA(0xffffffffffffe000, 0x00000001, 0x0001ffd7, PM_4K) # PCR (???)
+
+/*
+ * Initial mapping for Mips Magnum 4000PC systems.
+ * Do you believe me now that the Acer and Mips boxes are nearly the same ? :-)
+ * FIXME: Remove or merge some of the mappings.
+ */
+
+map0_magnum4000:
+ .word 8 # no. wired TLB entries
+ .word 0 # dummy
+
+MAPDATA(0xffffffffe1000000, 0x03ffc013, 0x00000001, 0x7e000) # 0
+MAPDATA(0xffffffffe0000000, 0x02000017, 0x00000001, 0x1e000) # 1 local I/O
+MAPDATA(0xffffffffe0100000, 0x03c00017, 0x00000001, 0) # 2 IRQ source
+MAPDATA(0xffffffffe0200000, 0x01800017, 0x01804017, 0x1fe000) # 3 local video ctrl
+MAPDATA(0xffffffffe0400000, 0x01808017, 0x0180c017, 0x1fe000) # 4 ext. video ctrl
+MAPDATA(0xffffffffe0800000, 0x01000017, 0x01010017, 0x7fe000) # 5 local video mem.
+MAPDATA(0xffffffffe2000000, 0x02400017, 0x02440017, 0x1ffe000) # 6 ISA I/O and mem.
+MAPDATA(0xffffffffffffe000, 0x00000001, 0x0001ffd7, 0) # 7 PCR
+
+
+ .text
+
+ .org 0x1000
+ .globl swapper_pg_dir
+swapper_pg_dir = . + (KSEG1-KSEG0)
+
+/*
+ * The page tables are initialized to only 4MB here - the final page
+ * tables are set up later depending on memory size.
+ */
+ .org 0x2000
+ EXPORT(pg0)
+
+ .org 0x3000
+ EXPORT(empty_bad_page)
+
+ .org 0x4000
+ EXPORT(empty_bad_page_table)
+
+ .org 0x5000
+ EXPORT(empty_zero_page)
+
+ .org 0x6000
+ EXPORT(invalid_pte_table)
+
+ .org 0x7000
+
+/*
+ * floppy_track_buffer is used to buffer one track of floppy data: it
+ * has to be separate from the tmp_floppy area, as otherwise a single-
+ * sector read/write can mess it up. It can contain one full cylinder (sic) of
+ * data (36*2*512 bytes).
+ */
+ EXPORT(floppy_track_buffer)
+ .fill 512*2*36,1,0
+
+ EXPORT(cache_error_buffer)
+ .fill 32*4,1,0
+
+ .data
+ EXPORT(kernelsp)
+ PTR 0
diff --git a/arch/mips/kernel/ioport.c b/arch/mips/kernel/ioport.c
new file mode 100644
index 000000000..ff6c0d518
--- /dev/null
+++ b/arch/mips/kernel/ioport.c
@@ -0,0 +1,36 @@
+/*
+ * linux/arch/mips/kernel/ioport.c
+ */
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+
+/*
+ * This changes the io permissions bitmap in the current task.
+ */
+asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
+{
+ return -ENOSYS;
+}
+
+unsigned int *stack;
+
+/*
+ * sys_iopl has to be used when you want to access the IO ports
+ * beyond the 0x3ff range: to get the full 65536 ports bitmapped
+ * you'd need 8kB of bitmaps/process, which is a bit excessive.
+ *
+ * Here we just change the eflags value on the stack: we allow
+ * only the super-user to do it. This depends on the stack-layout
+ * on system-call entry - see also fork() and the signal handling
+ * code.
+ */
+asmlinkage int sys_iopl(long ebx,long ecx,long edx,
+ long esi, long edi, long ebp, long eax, long ds,
+ long es, long fs, long gs, long orig_eax,
+ long eip,long cs,long eflags,long esp,long ss)
+{
+ return -ENOSYS;
+}
diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c
new file mode 100644
index 000000000..608a0b431
--- /dev/null
+++ b/arch/mips/kernel/irq.c
@@ -0,0 +1,334 @@
+/*
+ * linux/arch/mips/kernel/irq.c
+ *
+ * Copyright (C) 1992 Linus Torvalds
+ *
+ * This file contains the code used by various IRQ handling routines:
+ * asking for different IRQ's should be done through these routines
+ * instead of just grabbing them. Thus setups with different IRQ numbers
+ * shouldn't result in any weird surprises, and installing new handlers
+ * should be easier.
+ */
+
+/*
+ * IRQ's are in fact implemented a bit like signal handlers for the kernel.
+ * Naturally it's not a 1:1 relation, but there are similarities.
+ */
+
+/*
+ * Mips support by Ralf Baechle and Andreas Busse
+ *
+ * The Deskstation Tyne is almost completely like an IBM compatible PC with
+ * another type of microprocessor. Therefore this code is almost completely
+ * the same. More work needs to be done to support Acer PICA and other
+ * machines.
+ */
+
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+
+#include <asm/bitops.h>
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mipsregs.h>
+#include <asm/jazz.h>
+#include <asm/system.h>
+
+unsigned char cache_21 = 0xff;
+unsigned char cache_A1 = 0xff;
+
+unsigned long spurious_count = 0;
+
+void disable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+ unsigned char mask;
+
+ mask = 1 << (irq_nr & 7);
+ save_flags(flags);
+ if (irq_nr < 8) {
+ cli();
+ cache_21 |= mask;
+ outb(cache_21,0x21);
+ restore_flags(flags);
+ return;
+ }
+ cli();
+ cache_A1 |= mask;
+ outb(cache_A1,0xA1);
+ restore_flags(flags);
+}
+
+void enable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+ unsigned char mask;
+
+ mask = ~(1 << (irq_nr & 7));
+ save_flags(flags);
+ if (irq_nr < 8) {
+ cli();
+ cache_21 &= mask;
+ outb(cache_21,0x21);
+ restore_flags(flags);
+ return;
+ }
+ cli();
+ cache_A1 &= mask;
+ outb(cache_A1,0xA1);
+ restore_flags(flags);
+}
+
+/*
+ * Pointers to the low-level handlers: first the general ones, then the
+ * fast ones, then the bad ones.
+ */
+extern void interrupt(void);
+extern void fast_interrupt(void);
+extern void bad_interrupt(void);
+
+/*
+ * Initial irq handlers.
+ */
+struct irqaction {
+ void (*handler)(int, struct pt_regs *);
+ unsigned long flags;
+ unsigned long mask;
+ const char *name;
+};
+
+static struct irqaction irq_action[16] = {
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }
+};
+
+int get_irq_list(char *buf)
+{
+ int i, len = 0;
+ struct irqaction * action = irq_action;
+
+ for (i = 0 ; i < 16 ; i++, action++) {
+ if (!action->handler)
+ continue;
+ len += sprintf(buf+len, "%2d: %8d %c %s\n",
+ i, kstat.interrupts[i],
+ (action->flags & SA_INTERRUPT) ? '+' : ' ',
+ action->name);
+ }
+ return len;
+}
+
+/*
+ * do_IRQ handles IRQ's that have been installed without the
+ * SA_INTERRUPT flag: it uses the full signal-handling return
+ * and runs with other interrupts enabled. All relatively slow
+ * IRQ's should use this format: notably the keyboard/timer
+ * routines.
+ */
+asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
+{
+ struct irqaction * action = irq + irq_action;
+#if 0
+if (irq > 0) {
+ printk("in do_IRQ with irq=%d\n",irq);
+}
+#endif
+ kstat.interrupts[irq]++;
+ action->handler(irq, regs);
+}
+
+/*
+ * do_fast_IRQ handles IRQ's that don't need the fancy interrupt return
+ * stuff - the handler is also running with interrupts disabled unless
+ * it explicitly enables them later.
+ */
+asmlinkage void do_fast_IRQ(int irq)
+{
+ struct irqaction * action = irq + irq_action;
+
+ kstat.interrupts[irq]++;
+ action->handler(irq, NULL);
+}
+
+#define SA_PROBE SA_ONESHOT
+
+int request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
+ unsigned long irqflags, const char * devname)
+{
+ struct irqaction * action;
+ unsigned long flags;
+
+ if (irq > 15)
+ return -EINVAL;
+ action = irq + irq_action;
+ if (action->handler)
+ return -EBUSY;
+ if (!handler)
+ return -EINVAL;
+ save_flags(flags);
+ cli();
+ action->handler = handler;
+ action->flags = irqflags;
+ action->mask = 0;
+ action->name = devname;
+ if (!(action->flags & SA_PROBE)) { /* SA_ONESHOT is used by probing */
+ /*
+ * FIXME: Does the SA_INTERRUPT flag make any sense on MIPS???
+ */
+ if (action->flags & SA_INTERRUPT)
+ set_int_vector(irq,fast_interrupt);
+ else
+ set_int_vector(irq,interrupt);
+ }
+ if (irq < 8) {
+ cache_21 &= ~(1<<irq);
+ outb(cache_21,0x21);
+ } else {
+ cache_21 &= ~(1<<2);
+ cache_A1 &= ~(1<<(irq-8));
+ outb(cache_21,0x21);
+ outb(cache_A1,0xA1);
+ }
+ restore_flags(flags);
+ return 0;
+}
+
+void free_irq(unsigned int irq)
+{
+ struct irqaction * action = irq + irq_action;
+ unsigned long flags;
+
+ if (irq > 15) {
+ printk("Trying to free IRQ%d\n",irq);
+ return;
+ }
+ if (!action->handler) {
+ printk("Trying to free free IRQ%d\n",irq);
+ return;
+ }
+ save_flags(flags);
+ cli();
+ if (irq < 8) {
+ cache_21 |= 1 << irq;
+ outb(cache_21,0x21);
+ } else {
+ cache_A1 |= 1 << (irq-8);
+ outb(cache_A1,0xA1);
+ }
+ set_int_vector(irq,bad_interrupt);
+ action->handler = NULL;
+ action->flags = 0;
+ action->mask = 0;
+ action->name = NULL;
+ restore_flags(flags);
+}
+
+static void no_action(int cpl, struct pt_regs * regs) { }
+
+unsigned int probe_irq_on (void)
+{
+ unsigned int i, irqs = 0, irqmask;
+ unsigned long delay;
+
+ /* first, snaffle up any unassigned irqs */
+ for (i = 15; i > 0; i--) {
+ if (!request_irq(i, no_action, SA_PROBE, "probe")) {
+ enable_irq(i);
+ irqs |= (1 << i);
+ }
+ }
+
+ /* wait for spurious interrupts to mask themselves out again */
+ for (delay = jiffies + 2; delay > jiffies; ); /* min 10ms delay */
+
+ /* now filter out any obviously spurious interrupts */
+ irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
+ for (i = 15; i > 0; i--) {
+ if (irqs & (1 << i) & irqmask) {
+ irqs ^= (1 << i);
+ free_irq(i);
+ }
+ }
+#ifdef DEBUG
+ printk("probe_irq_on: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
+#endif
+ return irqs;
+}
+
+int probe_irq_off (unsigned int irqs)
+{
+ unsigned int i, irqmask;
+
+ irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
+ for (i = 15; i > 0; i--) {
+ if (irqs & (1 << i)) {
+ free_irq(i);
+ }
+ }
+#ifdef DEBUG
+ printk("probe_irq_off: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
+#endif
+ irqs &= irqmask;
+ if (!irqs)
+ return 0;
+ i = ffz(~irqs);
+ if (irqs != (irqs & (1 << i)))
+ i = -i;
+ return i;
+}
+
+void init_IRQ(void)
+{
+ int i;
+
+ switch (boot_info.machtype) {
+ case MACH_MIPS_MAGNUM_4000:
+ case MACH_ACER_PICA_61:
+ r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
+ JAZZ_IE_ETHERNET |
+ JAZZ_IE_SERIAL1 |
+ JAZZ_IE_SERIAL2 |
+ JAZZ_IE_PARALLEL |
+ JAZZ_IE_FLOPPY);
+ r4030_read_reg16(JAZZ_IO_IRQ_SOURCE); /* clear pending IRQs */
+ set_cp0_status(ST0_IM, IE_IRQ4 | IE_IRQ1);
+ /* set the clock to 100 Hz */
+ r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9);
+ break;
+ case MACH_DESKSTATION_TYNE:
+ /* set the clock to 100 Hz */
+ outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
+ outb_p(LATCH & 0xff , 0x40); /* LSB */
+ outb(LATCH >> 8 , 0x40); /* MSB */
+
+ if (request_irq(2, no_action, SA_INTERRUPT, "cascade"))
+ printk("Unable to get IRQ2 for cascade\n");
+ break;
+ default:
+ panic("Unknown machtype in init_IRQ");
+ }
+
+ for (i = 0; i < 16 ; i++)
+ set_int_vector(i, bad_interrupt);
+
+ /* initialize the bottom half routines. */
+ for (i = 0; i < 32; i++) {
+ bh_base[i].routine = NULL;
+ bh_base[i].data = NULL;
+ }
+ bh_active = 0;
+ intr_count = 0;
+}
diff --git a/arch/mips/kernel/jazzdma.c b/arch/mips/kernel/jazzdma.c
new file mode 100644
index 000000000..1d535e716
--- /dev/null
+++ b/arch/mips/kernel/jazzdma.c
@@ -0,0 +1,518 @@
+/*
+ * jazzdma.c
+ *
+ * Mips Jazz DMA controller support
+ * (C) 1995 Andreas Busse
+ *
+ * NOTE: Some of the argument checkings could be removed when
+ * things have settled down. Also, instead of returning 0xffffffff
+ * on failure of vdma_alloc() one could leave page #0 unused
+ * and return the more usual NULL pointer as logical address.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <asm/mipsregs.h>
+#include <asm/mipsconfig.h>
+#include <asm/jazz.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/dma.h>
+#include <asm/jazzdma.h>
+
+
+static unsigned long vdma_pagetable_start = 0;
+static unsigned long vdma_pagetable_end = 0;
+
+/*
+ * Debug stuff
+ */
+
+#define DEBUG_VDMA 0
+#define vdma_debug ((DEBUG_VDMA) ? debuglvl : 0)
+
+static int debuglvl = 3;
+
+/*
+ * Local prototypes
+ */
+
+static void vdma_pgtbl_init(void);
+
+
+/*
+ * Initialize the Jazz R4030 dma controller
+ */
+
+unsigned long vdma_init(unsigned long memory_start, unsigned long memory_end)
+{
+
+ /*
+ * Allocate 32k of memory for DMA page tables.
+ * This needs to be page aligned and should be
+ * uncached to avoid cache flushing after every
+ * update.
+ */
+
+ vdma_pagetable_start = KSEG1ADDR((memory_start + 4095) & ~ 4095);
+ vdma_pagetable_end = vdma_pagetable_start + VDMA_PGTBL_SIZE;
+
+
+ /*
+ * Clear the R4030 translation table
+ */
+
+ vdma_pgtbl_init();
+
+ r4030_write_reg32(JAZZ_R4030_TRSTBL_BASE,PHYSADDR(vdma_pagetable_start));
+ r4030_write_reg32(JAZZ_R4030_TRSTBL_LIM,VDMA_PGTBL_SIZE);
+ r4030_write_reg32(JAZZ_R4030_TRSTBL_INV,0);
+
+ printk("VDMA: R4030 DMA pagetables initialized.\n");
+ return(KSEG0ADDR(vdma_pagetable_end));
+}
+
+/*
+ * Allocate DMA pagetables using a simple first-fit algorithm
+ */
+
+unsigned long vdma_alloc(unsigned long paddr, unsigned long size)
+{
+ VDMA_PGTBL_ENTRY *entry = (VDMA_PGTBL_ENTRY *)vdma_pagetable_start;
+ int first;
+ int last;
+ int pages;
+ unsigned int frame;
+ unsigned long laddr;
+ int i;
+
+ /* check arguments */
+
+ if (paddr > 0x1fffffff) {
+ if (vdma_debug)
+ printk("vdma_alloc: Invalid physical address: %08lx\n",paddr);
+ return (VDMA_ERROR); /* invalid physical address */
+ }
+ if (size > 0x400000 || size == 0) {
+ if (vdma_debug)
+ printk("vdma_alloc: Invalid size: %08lx\n",size);
+ return (VDMA_ERROR); /* invalid physical address */
+ }
+
+ /* find free chunk */
+
+ pages = (size + 4095) >> 12; /* no. of pages to allocate */
+ first = 0;
+ while (1) {
+ while (entry[first].owner != VDMA_PAGE_EMPTY && first < VDMA_PGTBL_ENTRIES)
+ first++;
+ if (first+pages > VDMA_PGTBL_ENTRIES) /* nothing free */
+ return (VDMA_ERROR);
+
+ last = first+1;
+ while (entry[last].owner == VDMA_PAGE_EMPTY && last-first < pages)
+ last++;
+
+ if (last-first == pages)
+ break; /* found */
+ }
+
+ /* mark pages as allocated */
+
+ laddr = (first << 12) + (paddr & (VDMA_PAGESIZE-1));
+ frame = paddr & ~(VDMA_PAGESIZE-1);
+
+ for (i=first; i<last; i++) {
+ entry[i].frame = frame;
+ entry[i].owner = laddr;
+ frame += VDMA_PAGESIZE;
+ }
+
+ /*
+ * update translation table and
+ * return logical start address
+ */
+
+ r4030_write_reg32(JAZZ_R4030_TRSTBL_INV,0);
+
+ if (vdma_debug > 1)
+ printk("vdma_alloc: Allocated %d pages starting from %08lx\n",
+ pages,laddr);
+
+ if (vdma_debug > 2) {
+ printk("LADDR: ");
+ for (i=first; i<last; i++)
+ printk("%08x ",i<<12);
+ printk("\nPADDR: ");
+ for (i=first; i<last; i++)
+ printk("%08x ",entry[i].frame);
+ printk("\nOWNER: ");
+ for (i=first; i<last; i++)
+ printk("%08x ",entry[i].owner);
+ printk("\n");
+ }
+
+ return(laddr);
+}
+
+
+/*
+ * Free previously allocated dma translation pages
+ * Note that this does NOT change the translation table,
+ * it just marks the free'd pages as unused!
+ */
+
+int vdma_free(unsigned long laddr)
+{
+ VDMA_PGTBL_ENTRY *pgtbl = (VDMA_PGTBL_ENTRY *)vdma_pagetable_start;
+ int i;
+
+ i = laddr >> 12;
+
+ if (pgtbl[i].owner != laddr) {
+ printk("vdma_free: trying to free other's dma pages, laddr=%8lx\n",laddr);
+ return -1;
+ }
+
+ while (pgtbl[i].owner == laddr && i < VDMA_PGTBL_ENTRIES) {
+ pgtbl[i].owner = VDMA_PAGE_EMPTY;
+ i++;
+ }
+
+ if (vdma_debug > 1)
+ printk("vdma_free: freed %ld pages starting from %08lx\n",
+ i-(laddr>>12),laddr);
+
+ return 0;
+}
+
+/*
+ * Map certain page(s) to another physical address.
+ * Caller must have allocated the page(s) before.
+ */
+
+int vdma_remap(unsigned long laddr, unsigned long paddr, unsigned long size)
+{
+ VDMA_PGTBL_ENTRY *pgtbl = (VDMA_PGTBL_ENTRY *)vdma_pagetable_start;
+ int first;
+ int pages;
+
+ if (laddr > 0xffffff) {
+ if (vdma_debug)
+ printk("vdma_map: Invalid logical address: %08lx\n",laddr);
+ return -EINVAL; /* invalid logical address */
+ }
+ if (paddr > 0x1fffffff) {
+ if (vdma_debug)
+ printk("vdma_map: Invalid physical address: %08lx\n",paddr);
+ return -EINVAL; /* invalid physical address */
+ }
+
+ pages = (((paddr & (VDMA_PAGESIZE-1)) + size) >> 12) + 1;
+ first = laddr >> 12;
+ if (vdma_debug)
+ printk("vdma_remap: first=%x, pages=%x\n",first,pages);
+ if (first+pages > VDMA_PGTBL_ENTRIES) {
+ if (vdma_debug)
+ printk("vdma_alloc: Invalid size: %08lx\n",size);
+ return -EINVAL;
+ }
+
+ paddr &= ~(VDMA_PAGESIZE-1);
+ while (pages > 0 && first < VDMA_PGTBL_ENTRIES) {
+ if (pgtbl[first].owner != laddr) {
+ if (vdma_debug)
+ printk("Trying to remap other's pages.\n");
+ return -EPERM; /* not owner */
+ }
+ pgtbl[first].frame = paddr;
+ paddr += VDMA_PAGESIZE;
+ first++;
+ pages--;
+ }
+
+ /* update translation table */
+
+ r4030_write_reg32(JAZZ_R4030_TRSTBL_INV,0);
+
+
+ if (vdma_debug > 2) {
+ int i;
+ pages = (((paddr & (VDMA_PAGESIZE-1)) + size) >> 12) + 1;
+ first = laddr >> 12;
+ printk("LADDR: ");
+ for (i=first; i<first+pages; i++)
+ printk("%08x ",i<<12);
+ printk("\nPADDR: ");
+ for (i=first; i<first+pages; i++)
+ printk("%08x ",pgtbl[i].frame);
+ printk("\nOWNER: ");
+ for (i=first; i<first+pages; i++)
+ printk("%08x ",pgtbl[i].owner);
+ printk("\n");
+ }
+
+ return 0;
+}
+
+/*
+ * Translate a physical address to a logical address.
+ * This will return the logical address of the first
+ * match.
+ */
+
+unsigned long vdma_phys2log(unsigned long paddr)
+{
+ int i;
+ int frame;
+ VDMA_PGTBL_ENTRY *pgtbl = (VDMA_PGTBL_ENTRY *)vdma_pagetable_start;
+
+ frame = paddr & ~(VDMA_PAGESIZE-1);
+
+ for (i=0; i<VDMA_PGTBL_ENTRIES; i++) {
+ if (pgtbl[i].frame == frame)
+ break;
+ }
+
+ if (i == VDMA_PGTBL_ENTRIES)
+ return(0xffffffff);
+
+ return((i<<12) + (paddr & (VDMA_PAGESIZE-1)));
+}
+
+/*
+ * Translate a logical DMA address to a physical address
+ */
+unsigned long vdma_log2phys(unsigned long laddr)
+{
+ VDMA_PGTBL_ENTRY *pgtbl = (VDMA_PGTBL_ENTRY *)vdma_pagetable_start;
+
+ return(pgtbl[laddr >> 12].frame + (laddr & (VDMA_PAGESIZE-1)));
+}
+
+
+/*
+ * initialize the pagetable with a one-to-one mapping of
+ * the first 16 Mbytes of main memory and declare all
+ * entries to be unused. Using this method will at least
+ * allow some early device driver operations to work.
+ */
+
+static void vdma_pgtbl_init(void)
+{
+ int i;
+ unsigned long paddr = 0;
+ VDMA_PGTBL_ENTRY *pgtbl = (VDMA_PGTBL_ENTRY *)vdma_pagetable_start;
+
+ for (i=0; i<VDMA_PGTBL_ENTRIES; i++) {
+ pgtbl[i].frame = paddr;
+ pgtbl[i].owner = VDMA_PAGE_EMPTY;
+ paddr += VDMA_PAGESIZE;
+ }
+
+/* vdma_stats(); */
+}
+
+/*
+ * Print DMA statistics
+ */
+
+void vdma_stats(void)
+{
+ int i;
+
+ printk("vdma_stats: CONFIG: %08x\n",
+ r4030_read_reg32(JAZZ_R4030_CONFIG));
+ printk("R4030 translation table base: %08x\n",
+ r4030_read_reg32(JAZZ_R4030_TRSTBL_BASE));
+ printk("R4030 translation table limit: %08x\n",
+ r4030_read_reg32(JAZZ_R4030_TRSTBL_LIM));
+ printk("vdma_stats: INV_ADDR: %08x\n",
+ r4030_read_reg32(JAZZ_R4030_INV_ADDR));
+ printk("vdma_stats: R_FAIL_ADDR: %08x\n",
+ r4030_read_reg32(JAZZ_R4030_R_FAIL_ADDR));
+ printk("vdma_stats: M_FAIL_ADDR: %08x\n",
+ r4030_read_reg32(JAZZ_R4030_M_FAIL_ADDR));
+ printk("vdma_stats: IRQ_SOURCE: %08x\n",
+ r4030_read_reg32(JAZZ_R4030_IRQ_SOURCE));
+ printk("vdma_stats: I386_ERROR: %08x\n",
+ r4030_read_reg32(JAZZ_R4030_I386_ERROR));
+ printk("vdma_chnl_modes: ");
+ for (i=0; i<8; i++)
+ printk("%04x ",(unsigned)r4030_read_reg32(JAZZ_R4030_CHNL_MODE+(i<<5)));
+ printk("\n");
+ printk("vdma_chnl_enables: ");
+ for (i=0; i<8; i++)
+ printk("%04x ",(unsigned)r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(i<<5)));
+ printk("\n");
+}
+
+
+/*
+ * DMA transfer functions
+ */
+
+/*
+ * Enable a DMA channel. Also clear any error conditions.
+ */
+void vdma_enable(int channel)
+{
+ int status;
+
+ if (vdma_debug)
+ printk("vdma_enable: channel %d\n",channel);
+
+ /*
+ * Check error conditions first
+ */
+ status = r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5));
+ if (status & 0x400)
+ printk("VDMA: Channel %d: Address error!\n",channel);
+ if (status & 0x200)
+ printk("VDMA: Channel %d: Memory error!\n",channel);
+
+ /*
+ * Clear all interrupt flags
+ */
+ r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5),
+ R4030_TC_INTR | R4030_MEM_INTR | R4030_ADDR_INTR);
+
+ /*
+ * Enable the desired channel
+ */
+ r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5),
+ r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5)) |
+ R4030_CHNL_ENABLE);
+}
+
+/*
+ * Disable a DMA channel
+ */
+void vdma_disable(int channel)
+{
+ if (vdma_debug)
+ {
+ int status = r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5));
+
+ printk("vdma_disable: channel %d\n",channel);
+ printk("VDMA: channel %d status: %04x (%s) mode: %02x addr: %06x count: %06x\n",
+ channel,status,((status & 0x600) ? "ERROR" : "OK"),
+ (unsigned)r4030_read_reg32(JAZZ_R4030_CHNL_MODE+(channel<<5)),
+ (unsigned)r4030_read_reg32(JAZZ_R4030_CHNL_ADDR+(channel<<5)),
+ (unsigned)r4030_read_reg32(JAZZ_R4030_CHNL_COUNT+(channel<<5)));
+ }
+
+ r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5),
+ r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5)) &
+ ~R4030_CHNL_ENABLE);
+
+ /*
+ * After disabling a DMA channel a remote bus register should be
+ * read to ensure that the current DMA acknowledge cycle is completed.
+ */
+
+ *((volatile unsigned int *)JAZZ_DUMMY_DEVICE);
+}
+
+/*
+ * Set DMA mode. This function accepts the mode values used
+ * to set a PC-style DMA controller. For the SCSI and FDC
+ * channels, we also set the default modes each time we're
+ * called.
+ * NOTE: The FAST and BURST dma modes are supported by the
+ * R4030 Rev. 2 and PICA chipsets only. I leave them disabled
+ * for now.
+ */
+void vdma_set_mode(int channel, int mode)
+{
+ if (vdma_debug)
+ printk("vdma_set_mode: channel %d, mode 0x%x\n",channel,mode);
+
+ switch(channel)
+ {
+ case JAZZ_SCSI_DMA: /* scsi */
+ r4030_write_reg32(JAZZ_R4030_CHNL_MODE+(channel<<5),
+/* R4030_MODE_FAST | */
+/* R4030_MODE_BURST | */
+ R4030_MODE_INTR_EN |
+ R4030_MODE_WIDTH_16 |
+ R4030_MODE_ATIME_80);
+ break;
+
+ case JAZZ_FLOPPY_DMA: /* floppy */
+ r4030_write_reg32(JAZZ_R4030_CHNL_MODE+(channel<<5),
+/* R4030_MODE_FAST | */
+/* R4030_MODE_BURST | */
+ R4030_MODE_INTR_EN |
+ R4030_MODE_WIDTH_8 |
+ R4030_MODE_ATIME_120);
+ break;
+
+ case JAZZ_AUDIOL_DMA:
+ case JAZZ_AUDIOR_DMA:
+ printk("VDMA: Audio DMA not supported yet.\n");
+ break;
+
+ default:
+ printk("VDMA: vdma_set_mode() called with unsupported channel %d!\n",channel);
+ }
+
+ switch(mode)
+ {
+ case DMA_MODE_READ:
+ r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5),
+ r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5)) &
+ ~R4030_CHNL_WRITE);
+ break;
+
+ case DMA_MODE_WRITE:
+ r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5),
+ r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5)) |
+ R4030_CHNL_WRITE);
+ break;
+
+ default:
+ printk("VDMA: vdma_set_mode() called with unknown dma mode 0x%x\n",mode);
+ }
+}
+
+/*
+ * Set Transfer Address
+ */
+void vdma_set_addr(int channel, long addr)
+{
+ if (vdma_debug)
+ printk("vdma_set_addr: channel %d, addr %lx\n",channel,addr);
+
+ r4030_write_reg32(JAZZ_R4030_CHNL_ADDR+(channel<<5),addr);
+}
+
+/*
+ * Set Transfer Count
+ */
+void vdma_set_count(int channel, int count)
+{
+ if (vdma_debug)
+ printk("vdma_set_count: channel %d, count %08x\n",channel,(unsigned)count);
+
+ r4030_write_reg32(JAZZ_R4030_CHNL_COUNT+(channel<<5),count);
+}
+
+/*
+ * Get Residual
+ */
+int vdma_get_residue(int channel)
+{
+ int residual;
+
+ residual = r4030_read_reg32(JAZZ_R4030_CHNL_COUNT+(channel<<5));
+
+ if (vdma_debug)
+ printk("vdma_get_residual: channel %d: residual=%d\n",channel,residual);
+
+ return(residual);
+}
+
+
+/* end of file jazzdma.h */
diff --git a/arch/mips/kernel/magnum4000.S b/arch/mips/kernel/magnum4000.S
new file mode 100644
index 000000000..45e62d88d
--- /dev/null
+++ b/arch/mips/kernel/magnum4000.S
@@ -0,0 +1,261 @@
+/*
+ * arch/mips/kernel/magnum4000.S
+ *
+ * Copyright (C) 1995 Waldorf Electronics
+ * written by Ralf Baechle and Andreas Busse
+ */
+#include <asm/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/jazz.h>
+#include <asm/stackframe.h>
+
+/*
+ * mips_magnum_4000_handle_int: Interrupt handler for Mips Magnum 4000
+ */
+ .set noreorder
+
+ NESTED(mips_magnum_4000_handle_int, FR_SIZE, ra)
+ .set noat
+ SAVE_ALL
+ CLI
+ .set at
+
+ /*
+ * Get pending interrupts
+ */
+ mfc0 t0,CP0_CAUSE # get pending interrupts
+ mfc0 t1,CP0_STATUS # get enabled interrupts
+ and t0,t1 # isolate allowed ones
+ andi t0,0xff00 # isolate pending bits
+ beqz t0,spurious_interrupt
+ sll t0,16 # delay slot
+
+ /*
+ * Find irq with highest priority
+ * FIXME: This is slow
+ */
+ la t1,ll_vectors
+1: bltz t0,2f # found pending irq
+ sll t0,1
+ b 1b
+ subu t1,PTRSIZE # delay slot
+
+ /*
+ * Do the low-level stuff
+ */
+2: lw t0,(t1)
+ jr t0
+ nop # delay slot
+ END(mips_magnum_4000_handle_int)
+
+/*
+ * Used for keyboard driver's fake_keyboard_interrupt()
+ */
+ll_sw0: li s1,~IE_SW0
+ mfc0 t0,CP0_CAUSE
+ and t0,s1
+ mtc0 t0,CP0_CAUSE
+ PRINT("sw0 received...\n")
+ li t1,1
+ b call_real
+ li t3,PTRSIZE # delay slot, re-map to irq level 1
+
+ll_sw1: li s1,~IE_SW1
+ PANIC("Unimplemented sw1 handler")
+
+ll_local_dma: li s1,~IE_IRQ0
+ PANIC("Unimplemented local_dma handler")
+
+ll_local_dev: lbu t0,JAZZ_IO_IRQ_SOURCE
+#if __mips == 3
+ dsll t0,1
+ ld t0,local_vector(t0)
+#else /* 32 bit */
+ lw t0,local_vector(t0)
+#endif
+ jr t0
+ nop
+
+
+loc_no_irq: PANIC("Unimplemented loc_no_irq handler")
+loc_sound: PANIC("Unimplemented loc_sound handler")
+loc_video: PANIC("Unimplemented loc_video handler")
+loc_scsi: PANIC("Unimplemented loc_scsi handler")
+
+/*
+ * Keyboard interrupt handler
+ */
+loc_keyboard: li s1,~JAZZ_IE_KEYBOARD
+ li t1,JAZZ_KEYBOARD_IRQ
+ b loc_call
+ li t3,PTRSIZE*JAZZ_KEYBOARD_IRQ # delay slot
+
+/*
+ * Ethernet interrupt handler, remapped to level 2
+ */
+loc_ethernet: /* PRINT ("ethernet IRQ\n"); */
+ li s1,~JAZZ_IE_ETHERNET
+ li t1,JAZZ_ETHERNET_IRQ
+ b loc_call
+ li t3,PTRSIZE*JAZZ_ETHERNET_IRQ # delay slot
+
+
+loc_mouse: PANIC("Unimplemented loc_mouse handler")
+
+/*
+ * Serial port 1 IRQ, remapped to level 3
+ */
+loc_serial1: li s1,~JAZZ_IE_SERIAL1
+ li t1,JAZZ_SERIAL1_IRQ
+ b loc_call
+ li t3,PTRSIZE*JAZZ_SERIAL1_IRQ # delay slot
+
+/*
+ * Serial port 2 IRQ, remapped to level 4
+ */
+loc_serial2: li s1,~JAZZ_IE_SERIAL2
+ li t1,JAZZ_SERIAL2_IRQ
+ b loc_call
+ li t3,PTRSIZE*JAZZ_SERIAL2_IRQ # delay slot
+
+/*
+ * Parallel port IRQ, remapped to level 5
+ */
+loc_parallel: li s1,~JAZZ_IE_PARALLEL
+ li t1,JAZZ_PARALLEL_IRQ
+ b loc_call
+ li t3,PTRSIZE*JAZZ_PARALLEL_IRQ # delay slot
+
+/*
+ * Floppy IRQ, remapped to level 6
+ */
+loc_floppy: li s1,~JAZZ_IE_FLOPPY
+ li t1,JAZZ_FLOPPY_IRQ
+ b loc_call
+ li t3,PTRSIZE*JAZZ_FLOPPY_IRQ # delay slot
+
+/*
+ * Now call the real handler
+ */
+loc_call: lui s3,%hi(intr_count)
+ lw t2,%lo(intr_count)(s3)
+ la t0,IRQ_vectors # delay slot
+ addiu t2,1
+ sw t2,%lo(intr_count)(s3)
+
+ /*
+ * Temporarily disable interrupt source
+ */
+ lhu t2,JAZZ_IO_IRQ_ENABLE
+ addu t0,t3 # make ptr to IRQ handler
+ lw t0,(t0)
+ and t2,s1 # delay slot
+ sh t2,JAZZ_IO_IRQ_ENABLE
+ jalr t0 # call IRQ handler
+ nor s1,zero,s1 # delay slot
+
+ /*
+ * Reenable interrupt
+ */
+ lhu t2,JAZZ_IO_IRQ_ENABLE
+ lw t1,%lo(intr_count)(s3) # delay slot
+ or t2,s1
+ sh t2,JAZZ_IO_IRQ_ENABLE
+
+ subu t1,1
+ jr v0
+ sw t1,%lo(intr_count)(s3)
+
+ll_eisa_irq: li s1,~IE_IRQ2
+ PANIC("Unimplemented eisa_irq handler")
+
+ll_eisa_nmi: li s1,~IE_IRQ3
+ PANIC("Unimplemented eisa_nmi handler")
+
+/*
+ * Timer IRQ
+ * We remap the timer irq to be more similar to a IBM compatible
+ */
+ll_timer: lw t0,JAZZ_TIMER_REGISTER # timer irq cleared on read
+ li s1,~IE_IRQ4
+ li t1,0
+ b call_real
+ li t3,0 # delay slot, re-map to irq level 0
+
+/*
+ * CPU count/compare IRQ (unused)
+ */
+ll_count: j return
+ mtc0 zero,CP0_COMPARE
+
+/*
+ * Now call the real handler
+ */
+call_real: lui s3,%hi(intr_count)
+ lw t2,%lo(intr_count)(s3)
+ la t0,IRQ_vectors # delay slot
+ addiu t2,1
+ sw t2,%lo(intr_count)(s3)
+
+ /*
+ * temporarily disable interrupt
+ */
+ mfc0 t2,CP0_STATUS
+ and t2,s1
+
+ addu t0,t3
+ lw t0,(t0)
+ mtc0 t2,CP0_STATUS # delay slot
+ jalr t0
+ nor s1,zero,s1 # delay slot
+
+ /*
+ * reenable interrupt
+ */
+ mfc0 t2,CP0_STATUS
+ or t2,s1
+ mtc0 t2,CP0_STATUS
+
+ lw t2,%lo(intr_count)(s3)
+ subu t2,1
+
+ jr v0
+ sw t2,%lo(intr_count)(s3)
+
+/*
+ * Just for debugging...
+ */
+ LEAF(drawline)
+ li t1,0xffffffff
+ li t2,0x100
+1: sw t1,(a0)
+ addiu a0,a0,4
+ addiu t2,t2,-1
+ bnez t2,1b
+ nop
+ jr ra
+ nop
+ END(drawline)
+
+
+ .data
+ PTR ll_sw0 # SW0
+ PTR ll_sw1 # SW1
+ PTR ll_local_dma # Local DMA
+ PTR ll_local_dev # Local devices
+ PTR ll_eisa_irq # EISA IRQ
+ PTR ll_eisa_nmi # EISA NMI
+ PTR ll_timer # Timer
+ll_vectors: PTR ll_count # Count/Compare IRQ
+
+local_vector: PTR loc_no_irq
+ PTR loc_parallel
+ PTR loc_floppy
+ PTR loc_sound
+ PTR loc_video
+ PTR loc_ethernet
+ PTR loc_scsi
+ PTR loc_keyboard
+ PTR loc_mouse
+ PTR loc_serial1
+ PTR loc_serial2
diff --git a/arch/mips/kernel/pica.S b/arch/mips/kernel/pica.S
new file mode 100644
index 000000000..036aa3139
--- /dev/null
+++ b/arch/mips/kernel/pica.S
@@ -0,0 +1,252 @@
+/*
+ * arch/mips/kernel/pica.S
+ *
+ * Copyright (C) 1995 Waldorf Electronics
+ * written by Ralf Baechle and Andreas Busse
+ *
+ * Acer PICA 61 specific stuff
+ */
+#include <asm/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/jazz.h>
+#include <asm/pica.h>
+#include <asm/stackframe.h>
+
+/*
+ * acer_pica_61_handle_int: Interrupt handler for the ACER Pica-61 boards
+ * FIXME: this is *very* experimental!
+ */
+ .set noreorder
+
+ NESTED(acer_pica_61_handle_int, FR_SIZE, ra)
+ .set noat
+ SAVE_ALL
+ CLI
+ .set at
+
+ /*
+ * Get pending interrupts
+ */
+ mfc0 t0,CP0_CAUSE # get pending interrupts
+ mfc0 t1,CP0_STATUS # get enabled interrupts
+ and t0,t1 # isolate allowed ones
+ andi t0,0xff00 # isolate pending bits
+ beqz t0,spurious_interrupt
+ sll t0,16 # delay slot
+
+ /*
+ * Find irq with highest priority
+ * FIXME: This is slow - use binary search
+ */
+ la t1,ll_vectors
+1: bltz t0,2f # found pending irq
+ sll t0,1
+ b 1b
+ subu t1,PTRSIZE # delay slot
+
+ /*
+ * Do the low-level stuff
+ */
+2: lw t0,(t1)
+ jr t0
+ nop # delay slot
+ END(acer_pica_61_handle_int)
+
+/*
+ * Used for keyboard driver's fake_keyboard_interrupt()
+ */
+ll_sw0: li s1,~IE_SW0
+ mfc0 t0,CP0_CAUSE
+ and t0,s1
+ mtc0 t0,CP0_CAUSE
+ PRINT("sw0 received...\n")
+ li t1,1
+ b call_real
+ li t3,PTRSIZE # delay slot, re-map to irq level 1
+
+ll_sw1: li s1,~IE_SW1
+ PANIC("Unimplemented sw1 handler")
+
+ll_local_dma: li s1,~IE_IRQ0
+ PANIC("Unimplemented local_dma handler")
+
+ll_local_dev: lbu t0,JAZZ_IO_IRQ_SOURCE
+#if __mips == 3
+ dsll t0,1
+ ld t0,local_vector(t0)
+#else /* 32 bit */
+ lw t0,local_vector(t0)
+#endif
+ jr t0
+ nop
+
+
+loc_no_irq: PANIC("Unimplemented loc_no_irq handler")
+/*
+ * Parallel port IRQ, remapped to level 5
+ */
+loc_parallel: li s1,~JAZZ_IE_PARALLEL
+ li t1,JAZZ_PARALLEL_IRQ
+ b loc_call
+ li t3,PTRSIZE*JAZZ_PARALLEL_IRQ # delay slot
+
+/*
+ * Floppy IRQ, remapped to level 6
+ */
+loc_floppy: li s1,~JAZZ_IE_FLOPPY
+ li t1,JAZZ_FLOPPY_IRQ
+ b loc_call
+ li t3,PTRSIZE*JAZZ_FLOPPY_IRQ # delay slot
+
+/*
+ * Now call the real handler
+ */
+loc_call: lui s3,%hi(intr_count)
+ lw t2,%lo(intr_count)(s3)
+ la t0,IRQ_vectors # delay slot
+ addiu t2,1
+ sw t2,%lo(intr_count)(s3)
+
+ /*
+ * Temporarily disable interrupt source
+ */
+ lhu t2,JAZZ_IO_IRQ_ENABLE
+ addu t0,t3 # make ptr to IRQ handler
+ lw t0,(t0)
+ and t2,s1 # delay slot
+ sh t2,JAZZ_IO_IRQ_ENABLE
+ jalr t0 # call IRQ handler
+ nor s1,zero,s1 # delay slot
+
+ /*
+ * Reenable interrupt
+ */
+ lhu t2,JAZZ_IO_IRQ_ENABLE
+ lw t1,%lo(intr_count)(s3) # delay slot
+ or t2,s1
+ sh t2,JAZZ_IO_IRQ_ENABLE
+
+ subu t1,1
+ jr v0
+ sw t1,%lo(intr_count)(s3) # delay slot
+
+ll_isa_irq: li s1,~IE_IRQ2
+ PANIC("Unimplemented isa_irq handler")
+
+ll_isa_nmi: li s1,~IE_IRQ3
+ PANIC("Unimplemented isa_nmi handler")
+
+/*
+ * Timer IRQ
+ * We remap the timer irq to be more similar to an IBM compatible
+ */
+ll_timer: lw zero,JAZZ_TIMER_REGISTER # timer irq cleared on read
+ li s1,~IE_IRQ4
+ li t1,0
+ b call_real
+ li t3,0 # delay slot, re-map to irq level 0
+
+/*
+ * CPU count/compare IRQ (unused)
+ */
+ll_count: j return
+ mtc0 zero,CP0_COMPARE
+
+/*
+ * Now call the real handler
+ */
+call_real: lui s3,%hi(intr_count)
+ lw t2,%lo(intr_count)(s3)
+ la t0,IRQ_vectors
+ addiu t2,1
+ sw t2,%lo(intr_count)(s3)
+
+ /*
+ * temporarily disable interrupt
+ */
+ mfc0 t2,CP0_STATUS
+ and t2,s1
+
+ addu t0,t3
+ lw t0,(t0)
+ mtc0 t2,CP0_STATUS # delay slot
+ jalr t0
+ nor s1,zero,s1 # delay slot
+
+ /*
+ * reenable interrupt
+ */
+ mfc0 t2,CP0_STATUS
+ or t2,s1
+ mtc0 t2,CP0_STATUS
+
+ lw t2,%lo(intr_count)(s3)
+ subu t2,1
+
+ jr v0
+ sw t2,%lo(intr_count)(s3)
+
+ .data
+ PTR ll_sw0 # SW0
+ PTR ll_sw1 # SW1
+ PTR ll_local_dma # Local DMA
+ PTR ll_local_dev # Local devices
+ PTR ll_isa_irq # ISA IRQ
+ PTR ll_isa_nmi # ISA NMI
+ PTR ll_timer # Timer
+ll_vectors: PTR ll_count # Count/Compare IRQ
+
+
+/*
+ * Sound? What sound hardware (whistle) ???
+ */
+loc_sound: PANIC("Unimplemented loc_sound handler")
+loc_video: PANIC("Unimplemented loc_video handler")
+
+/*
+ * Ethernet interrupt handler, remapped to level 2
+ */
+loc_ethernet: li s1,~JAZZ_IE_ETHERNET
+ li t1,JAZZ_ETHERNET_IRQ
+ b loc_call
+ li t3,PTRSIZE*JAZZ_ETHERNET_IRQ # delay slot
+
+loc_scsi: PANIC("Unimplemented loc_scsi handler")
+
+/*
+ * Keyboard interrupt handler
+ */
+loc_keyboard: li s1,~JAZZ_IE_KEYBOARD
+ li t1,JAZZ_KEYBOARD_IRQ
+ b loc_call
+ li t3,PTRSIZE*JAZZ_KEYBOARD_IRQ # re-map to irq level 1
+
+loc_mouse: PANIC("Unimplemented loc_mouse handler")
+
+/*
+ * Serial port 1 IRQ, remapped to level 3
+ */
+loc_serial1: li s1,~JAZZ_IE_SERIAL1
+ li t1,JAZZ_SERIAL1_IRQ
+ b loc_call
+ li t3,PTRSIZE*JAZZ_SERIAL1_IRQ # delay slot
+
+/*
+ * Serial port 2 IRQ, remapped to level 4
+ */
+loc_serial2: li s1,~JAZZ_IE_SERIAL2
+ li t1,JAZZ_SERIAL2_IRQ
+ b loc_call
+ li t3,PTRSIZE*JAZZ_SERIAL2_IRQ # delay slot
+
+local_vector: PTR loc_no_irq
+ PTR loc_parallel
+ PTR loc_floppy
+ PTR loc_sound
+ PTR loc_video
+ PTR loc_ethernet
+ PTR loc_scsi
+ PTR loc_keyboard
+ PTR loc_mouse
+ PTR loc_serial1
+ PTR loc_serial2
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
new file mode 100644
index 000000000..dd69c3208
--- /dev/null
+++ b/arch/mips/kernel/process.c
@@ -0,0 +1,216 @@
+/*
+ * linux/arch/mips/kernel/process.c
+ *
+ * Copyright (C) 1995 Ralf Baechle
+ * written by Ralf Baechle
+ */
+
+/*
+ * This file handles the architecture-dependent parts of process handling..
+ */
+
+#include <linux/errno.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/malloc.h>
+#include <linux/ldt.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+
+#include <asm/bootinfo.h>
+#include <asm/segment.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/mipsregs.h>
+#include <asm/processor.h>
+#include <asm/stackframe.h>
+#include <asm/io.h>
+
+asmlinkage void ret_from_sys_call(void);
+
+asmlinkage int sys_pipe(unsigned long * fildes)
+{
+ int fd[2];
+ int error;
+
+ error = verify_area(VERIFY_WRITE,fildes,8);
+ if (error)
+ return error;
+ error = do_pipe(fd);
+ if (error)
+ return error;
+ put_fs_long(fd[0],0+fildes);
+ put_fs_long(fd[1],1+fildes);
+ return 0;
+}
+
+asmlinkage int sys_idle(void)
+{
+ if (current->pid != 0)
+ return -EPERM;
+
+ /* endless idle loop with no priority at all */
+ current->counter = -100;
+ for (;;) {
+ /*
+ * R4[26]00 have wait, R4[04]00 don't.
+ */
+ if (wait_available && !need_resched)
+ __asm__(".set\tmips3\n\t"
+ "wait\n\t"
+ ".set\tmips0\n\t");
+ schedule();
+ }
+}
+
+/*
+ * This routine reboots the machine by asking the keyboard
+ * controller to pulse the reset-line low. We try that for a while,
+ * and if it doesn't work, we do some other stupid things.
+ * Should be ok for Deskstation Tynes. Reseting others needs to be
+ * investigated...
+ */
+static inline void kb_wait(void)
+{
+ int i;
+
+ for (i=0; i<0x10000; i++)
+ if ((inb_p(0x64) & 0x02) == 0)
+ break;
+}
+
+/*
+ * Hard reset for Deskstation Tyne
+ * No hint how this works on Pica boards.
+ */
+void hard_reset_now(void)
+{
+ int i, j;
+
+ sti();
+ for (;;) {
+ for (i=0; i<100; i++) {
+ kb_wait();
+ for(j = 0; j < 100000 ; j++)
+ /* nothing */;
+ outb(0xfe,0x64); /* pulse reset low */
+ }
+ }
+}
+
+void show_regs(struct pt_regs * regs)
+{
+ /*
+ * Saved main processor registers
+ */
+ printk("$0 : %08x %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ 0, 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\n",
+ regs->reg24, regs->reg25, 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);
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+void exit_thread(void)
+{
+ /*
+ * Nothing to do
+ */
+}
+
+void flush_thread(void)
+{
+ /*
+ * Nothing to do
+ */
+}
+
+void copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+ struct task_struct * p, struct pt_regs * regs)
+{
+ struct pt_regs * childregs;
+
+ /*
+ * set up new TSS
+ */
+ childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1;
+ *childregs = *regs;
+ childregs->reg2 = 0;
+ regs->reg2 = p->pid;
+ childregs->reg29 = usp;
+ p->tss.ksp = (p->kernel_stack_page + PAGE_SIZE - 8);
+ p->tss.reg29 = (unsigned long) childregs; /* new sp */
+ p->tss.reg31 = (unsigned long) ret_from_sys_call;
+
+ /*
+ * New tasks loose permission to use the fpu. This accelerates context
+ * switching for most programs since they don't use the fpu.
+ */
+ p->tss.cp0_status = read_32bit_cp0_register(CP0_STATUS) &
+ ~(ST0_CU3|ST0_CU2|ST0_CU1|ST0_KSU|ST0_ERL|ST0_EXL);
+ childregs->cp0_status &= ~(ST0_CU3|ST0_CU2|ST0_CU1);
+}
+
+/*
+ * fill in the user structure for a core dump..
+ */
+void dump_thread(struct pt_regs * regs, struct user * dump)
+{
+ /*
+ * To do...
+ */
+}
+
+asmlinkage int sys_fork(struct pt_regs regs)
+{
+ return do_fork(COPYVM | SIGCHLD, regs.reg29, &regs);
+}
+
+asmlinkage int sys_clone(struct pt_regs regs)
+{
+ unsigned long clone_flags;
+ unsigned long newsp;
+
+ newsp = regs.reg4;
+ clone_flags = regs.reg5;
+ if (!newsp)
+ newsp = regs.reg29;
+ if (newsp == regs.reg29)
+ clone_flags |= COPYVM;
+ return do_fork(clone_flags, newsp, &regs);
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+asmlinkage int sys_execve(struct pt_regs regs)
+{
+ int error;
+ char * filename;
+
+ error = getname((char *) regs.reg4, &filename);
+ if (error)
+ return error;
+ error = do_execve(filename, (char **) regs.reg5, (char **) regs.reg6, &regs);
+ putname(filename);
+ return error;
+}
diff --git a/arch/mips/ptrace.c b/arch/mips/kernel/ptrace.c
index 0a42b9c38..6f35ceb67 100644
--- a/arch/mips/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -11,6 +11,7 @@
#include <linux/user.h>
#include <asm/segment.h>
+#include <asm/pgtable.h>
#include <asm/system.h>
#if 0
@@ -84,23 +85,30 @@ static inline int put_stack_long(struct task_struct *task, int offset,
*/
static unsigned long get_long(struct vm_area_struct * vma, unsigned long addr)
{
+ pgd_t * pgdir;
+ pte_t * pgtable;
unsigned long page;
repeat:
- page = *PAGE_DIR_OFFSET(vma->vm_task->tss.cr3, addr);
- if (page & PAGE_PRESENT) {
- page &= PAGE_MASK;
- page += PAGE_PTR(addr);
- page = *((unsigned long *) page);
+ pgdir = PAGE_DIR_OFFSET(vma->vm_task, addr);
+ if (pgd_none(*pgdir)) {
+ do_no_page(vma, addr, 0);
+ goto repeat;
+ }
+ if (pgd_bad(*pgdir)) {
+ printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
+ pgd_clear(pgdir);
+ return 0;
}
- if (!(page & PAGE_PRESENT)) {
+ pgtable = (pte_t *) (PAGE_PTR(addr) + pgd_page(*pgdir));
+ if (!pte_present(*pgtable)) {
do_no_page(vma, addr, 0);
goto repeat;
}
+ page = pte_page(*pgtable);
/* this is a hack for non-kernel-mapped video buffers and similar */
if (page >= high_memory)
return 0;
- page &= PAGE_MASK;
page += addr & ~PAGE_MASK;
return *(unsigned long *) page;
}
@@ -117,52 +125,50 @@ repeat:
static void put_long(struct vm_area_struct * vma, unsigned long addr,
unsigned long data)
{
- unsigned long page, pte = 0;
- int readonly = 0;
+ pgd_t *pgdir;
+ pte_t *pgtable;
+ unsigned long page;
repeat:
- page = *PAGE_DIR_OFFSET(vma->vm_task->tss.cr3, addr);
- if (page & PAGE_PRESENT) {
- page &= PAGE_MASK;
- page += PAGE_PTR(addr);
- pte = page;
- page = *((unsigned long *) page);
+ pgdir = PAGE_DIR_OFFSET(vma->vm_task, addr);
+ if (!pgd_present(*pgdir)) {
+ do_no_page(vma, addr, 1);
+ goto repeat;
+ }
+ if (pgd_bad(*pgdir)) {
+ printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
+ pgd_clear(pgdir);
+ return;
}
- if (!(page & PAGE_PRESENT)) {
- do_no_page(vma, addr, 0 /* PAGE_RW */);
+ pgtable = (pte_t *) (PAGE_PTR(addr) + pgd_page(*pgdir));
+ if (!pte_present(*pgtable)) {
+ do_no_page(vma, addr, 1);
goto repeat;
}
- if (!(page & PAGE_RW)) {
- if (!(page & PAGE_COW))
- readonly = 1;
- do_wp_page(vma, addr, PAGE_RW | PAGE_PRESENT);
+ page = pte_page(*pgtable);
+ if (!pte_write(*pgtable)) {
+ do_wp_page(vma, addr, 1);
goto repeat;
}
/* this is a hack for non-kernel-mapped video buffers and similar */
- if (page >= high_memory)
- return;
+ if (page < high_memory) {
+ page += addr & ~PAGE_MASK;
+ *(unsigned long *) page = data;
+ }
/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
- *(unsigned long *) pte |= (PAGE_DIRTY|PAGE_COW);
- page &= PAGE_MASK;
- page += addr & ~PAGE_MASK;
- *(unsigned long *) page = data;
- if (readonly) {
- *(unsigned long *) pte &=~ (PAGE_RW|PAGE_COW);
- invalidate();
- }
+/* this should also re-instate whatever read-only mode there was before */
+ *pgtable = pte_mkdirty(mk_pte(page, vma->vm_page_prot));
+ invalidate();
}
-static struct vm_area_struct * find_vma(struct task_struct * tsk, unsigned long addr)
+static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr)
{
struct vm_area_struct * vma;
addr &= PAGE_MASK;
- for (vma = tsk->mm->mmap ; ; vma = vma->vm_next) {
- if (!vma)
- return NULL;
- if (vma->vm_end > addr)
- break;
- }
+ vma = find_vma(tsk, addr);
+ if (!vma)
+ return NULL;
if (vma->vm_start <= addr)
return vma;
if (!(vma->vm_flags & VM_GROWSDOWN))
@@ -181,7 +187,7 @@ static struct vm_area_struct * find_vma(struct task_struct * tsk, unsigned long
static int read_long(struct task_struct * tsk, unsigned long addr,
unsigned long * result)
{
- struct vm_area_struct * vma = find_vma(tsk, addr);
+ struct vm_area_struct * vma = find_extend_vma(tsk, addr);
if (!vma)
return -EIO;
@@ -223,7 +229,7 @@ static int read_long(struct task_struct * tsk, unsigned long addr,
static int write_long(struct task_struct * tsk, unsigned long addr,
unsigned long data)
{
- struct vm_area_struct * vma = find_vma(tsk, addr);
+ struct vm_area_struct * vma = find_extend_vma(tsk, addr);
if (!vma)
return -EIO;
diff --git a/arch/mips/kernel/r4xx0.S b/arch/mips/kernel/r4xx0.S
new file mode 100644
index 000000000..a68b32243
--- /dev/null
+++ b/arch/mips/kernel/r4xx0.S
@@ -0,0 +1,732 @@
+/*
+ * arch/mips/kernel/r4xx0.S
+ *
+ * Copyright (C) 1994, 1995 Waldorf Electronics
+ * Written by Ralf Baechle and Andreas Busse
+ *
+ * This file contains most of the R4xx0 specific routines.
+ *
+ * This code is evil magic. Read appendix f (coprozessor 0 hazards) of
+ * all R4xx0 manuals and think about that MIPS means "Microprocessor without
+ * Interlocked Pipeline Stages" before you even think about changing this code!
+ */
+#include <linux/autoconf.h>
+
+#include <asm/asm.h>
+#include <asm/bootinfo.h>
+#include <asm/cachectl.h>
+#include <asm/mipsconfig.h>
+#include <asm/mipsregs.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/mipsregs.h>
+#include <asm/segment.h>
+#include <asm/stackframe.h>
+
+MODE_ALIAS = 0x0016 # uncachable
+
+ .text
+ .set mips3
+ .set noreorder
+
+ .align 5
+ NESTED(handle_tlbl, FR_SIZE, sp)
+ .set noat
+ /*
+ * Check whether this is a refill or an invalid exception
+ *
+ * NOTE: Some MIPS manuals say that the R4x00 sets the
+ * BadVAddr only when EXL == 0. This is wrong - BadVAddr
+ * is being set for all Reload, Invalid and Modified
+ * exceptions.
+ */
+ mfc0 k0,CP0_BADVADDR
+ mfc0 k1,CP0_ENTRYHI
+ ori k0,0x1fff
+ xori k0,0x1fff
+ andi k1,0xff
+ or k0,k1
+ mfc0 k1,CP0_ENTRYHI
+ mtc0 k0,CP0_ENTRYHI
+ nop # for R4[04]00 pipeline
+ nop
+ nop
+ tlbp
+ nop # for R4[04]00 pipeline
+ nop
+ mfc0 k0,CP0_INDEX
+ bgez k0,invalid_tlbl # bad addr in c0_badvaddr
+ mtc0 k1,CP0_ENTRYHI # delay slot
+ /*
+ * Damn... The next nop is required on my R4400PC V5.0, but
+ * I don't know why - at least there is no documented
+ * reason as for the others :-(
+ */
+ nop
+
+#ifdef CONFIG_DEBUG_TLB
+ /*
+ * OK, this is a double fault. Let's see whether this is
+ * due to an invalid entry in the page_table.
+ */
+ dmfc0 k0,CP0_BADVADDR
+ srl k0,12
+ sll k0,2
+ lui k1,%HI(TLBMAP)
+ addu k0,k1
+ lw k1,(k0)
+ andi k1,(_PAGE_PRESENT|_PAGE_ACCESSED)
+ bnez k1,reload_pgd_entries
+ nop # delay slot
+
+ .set noat
+ SAVE_ALL
+ .set at
+ PRINT("Double fault caused by invalid entries in pgd:\n")
+ dmfc0 a1,CP0_BADVADDR
+ PRINT("Double fault address : %08lx\n")
+ dmfc0 a1,CP0_EPC
+ PRINT("c0_epc : %08lx\n")
+ jal show_regs
+ move a0,sp
+ .set noat
+ STI
+ .set at
+ PANIC("Corrupted pagedir")
+ .set noat
+
+reload_pgd_entries:
+#endif /* CONFIG_DEBUG_TLB */
+
+ /*
+ * Load missing pair of entries from the pgd and return.
+ */
+ dmfc0 k1,CP0_CONTEXT
+ dsra k1,1
+ lwu k0,(k1) # Never causes nested exception
+ lwu k1,4(k1)
+ dsrl k0,6 # Convert to EntryLo format
+ dsrl k1,6 # Convert to EntryLo format
+ dmtc0 k0,CP0_ENTRYLO0
+ dmtc0 k1,CP0_ENTRYLO1
+ nop # for R4[04]00 pipeline
+ tlbwr
+ nop # for R4[04]00 pipeline
+ nop
+ nop
+ /*
+ * We don't know whether the original access was read or
+ * write, so return and see what happens...
+ */
+ eret
+
+ /*
+ * Handle invalid exception
+ *
+ * There are two possible causes for an invalid (tlbl)
+ * exception:
+ * 1) pages with present bit set but the valid bit clear
+ * 2) nonexistant pages
+ * Case one needs fast handling, therefore don't save
+ * registers yet.
+ *
+ * k0 contains c0_index.
+ */
+invalid_tlbl: /*
+ * Remove entry so we don't need to care later
+ * For sake of the R4000 V2.2 pipeline the tlbwi insn
+ * has been moved down. Moving it around is juggling with
+ * explosives...
+ */
+ lui k1,0x0008
+ or k0,k1
+ dsll k0,13
+ dmtc0 k0,CP0_ENTRYHI
+ dmtc0 zero,CP0_ENTRYLO0
+ dmtc0 zero,CP0_ENTRYLO1
+ /*
+ * Test present bit in entry
+ */
+ dmfc0 k0,CP0_BADVADDR
+ srl k0,12
+ sll k0,2
+ tlbwi # do not move!
+ lui k1,%HI(TLBMAP)
+ addu k0,k1
+ lw k1,(k0)
+ andi k1,(_PAGE_PRESENT|_PAGE_READ)
+ xori k1,(_PAGE_PRESENT|_PAGE_READ)
+ bnez k1,nopage_tlbl
+ /*
+ * Present and read bits are set -> set valid and accessed bits
+ */
+ lw k1,(k0) # delay slot
+ ori k1,(_PAGE_VALID|_PAGE_ACCESSED)
+ sw k1,(k0)
+ eret
+
+ /*
+ * Page doesn't exist. Lots of work which is less important
+ * for speed needs to be done, so hand it all over to the
+ * kernel memory management routines.
+ */
+nopage_tlbl: SAVE_ALL
+ STI
+ .set at
+ /*
+ * a0 (struct pt_regs *) regs
+ * a1 (unsigned long) 0 for read access
+ */
+ move a0,sp
+ jal do_page_fault
+ li a1,0 # delay slot
+ j ret_from_sys_call
+ nop # delay slot
+ END(handle_tlbl)
+
+ .text
+ .align 5
+ NESTED(handle_tlbs, FR_SIZE, sp)
+ .set noat
+ /*
+ * It is impossible that is a nested reload exception.
+ * Therefore this must be a invalid exception.
+ * Two possible cases:
+ * 1) Page exists but not dirty.
+ * 2) Page doesn't exist yet. Hand over to the kernel.
+ *
+ * Test whether present bit in entry is set
+ */
+ dmfc0 k0,CP0_BADVADDR
+ srl k0,12
+ sll k0,2
+ lui k1,%HI(TLBMAP)
+ addu k0,k1
+ lw k1,(k0)
+ tlbp # find faulting entry
+ andi k1,(_PAGE_PRESENT|_PAGE_WRITE)
+ xori k1,(_PAGE_PRESENT|_PAGE_WRITE)
+ bnez k1,nopage_tlbs
+ /*
+ * Present and writable bits set: set accessed and dirty bits.
+ */
+ lw k1,(k0) # delay slot
+ ori k1,k1,(_PAGE_ACCESSED|_PAGE_MODIFIED| \
+ _PAGE_VALID|_PAGE_DIRTY)
+ sw k1,(k0)
+ /*
+ * Now reload the entry into the TLB
+ */
+ ori k0,0x0004
+ xori k0,0x0004
+ lw k1,4(k0)
+ lw k0,(k0)
+ srl k1,6
+ srl k0,6
+ dmtc0 k1,CP0_ENTRYLO1
+ dmtc0 k0,CP0_ENTRYLO0
+ nop # for R4[04]00 pipeline
+ tlbwi
+ nop # for R4[04]00 pipeline
+ nop
+ nop
+ eret
+
+ /*
+ * Page doesn't exist. Lots of work which is less important
+ * for speed needs to be done, so hand it all over to the
+ * kernel memory management routines.
+ */
+nopage_tlbs:
+#if 0
+ .set mips3
+ SAVE_ALL
+ .set mips0
+ PRINT("nopage_tlbs\n")
+ .set mips3
+ RESTORE_ALL
+ .set mips3
+ j 1f
+ nop
+#endif
+nowrite_mod:
+#if 0
+ .set mips3
+ SAVE_ALL
+ .set mips0
+ PRINT("nopage_mod\n")
+ .set mips3
+ RESTORE_ALL
+ .set mips3
+ j 1f
+ nop
+1:
+#endif
+ /*
+ * Remove entry so we don't need to care later
+ */
+ mfc0 k0,CP0_INDEX
+#ifdef CONFIG_DEBUG_TLB
+ bgez k0,2f
+ nop
+ /*
+ * We got a tlbs exception but found no matching entry in
+ * the tlb. This should never happen. Paranoia makes us
+ * check it, though.
+ */
+ SAVE_ALL
+ jal show_regs
+ move a0,sp
+ .set at
+ mfc0 a1,CP0_BADVADDR
+ PRINT("c0_badvaddr == %08lx\n")
+ mfc0 a1,CP0_INDEX
+ PRINT("c0_index == %08x\n")
+ mfc0 a1,CP0_ENTRYHI
+ PRINT("c0_entryhi == %08x\n")
+ jal dump_tlb_nonwired
+ nop
+ .set noat
+ STI
+ .set at
+ PANIC("Tlbs or tlbm exception with no matching entry in tlb")
+1: j 1b
+ nop
+2:
+#endif /* CONFIG_DEBUG_TLB */
+ lui k1,0x0008
+ or k0,k1
+ dsll k0,13
+ dmtc0 k0,CP0_ENTRYHI
+ dmtc0 zero,CP0_ENTRYLO0
+ dmtc0 zero,CP0_ENTRYLO1
+ nop # for R4[04]00 pipeline
+ nop # R4000 V2.2 requires 4 NOPs
+ nop
+ nop
+ tlbwi
+ .set noat
+ SAVE_ALL
+ STI
+ .set at
+ /*
+ * a0 (struct pt_regs *) regs
+ * a1 (unsigned long) 1 for write access
+ */
+ move a0,sp
+ jal do_page_fault
+ li a1,1 # delay slot
+ j ret_from_sys_call
+ nop # delay slot
+ END(handle_tlbs)
+
+ .align 5
+ NESTED(handle_mod, FR_SIZE, sp)
+ .set noat
+ /*
+ * Two possible cases:
+ * 1) Page is writable but not dirty -> set dirty and return
+ * 2) Page is not writable -> call C handler
+ */
+ dmfc0 k0,CP0_BADVADDR
+ srl k0,12
+ sll k0,2
+ lui k1,%HI(TLBMAP)
+ addu k0,k1
+ lw k1,(k0)
+ tlbp # find faulting entry
+ andi k1,_PAGE_WRITE
+ beqz k1,nowrite_mod
+ /*
+ * Present and writable bits set: set accessed and dirty bits.
+ */
+ lw k1,(k0) # delay slot
+ ori k1,(_PAGE_ACCESSED|_PAGE_DIRTY)
+ sw k1,(k0)
+ /*
+ * Now reload the entry into the tlb
+ */
+ ori k0,0x0004
+ xori k0,0x0004
+ lw k1,4(k0)
+ lw k0,(k0)
+ srl k1,6
+ srl k0,6
+ dmtc0 k1,CP0_ENTRYLO1
+ dmtc0 k0,CP0_ENTRYLO0
+ nop # for R4[04]00 pipeline
+ nop
+ nop
+ tlbwi
+ nop # for R4[04]00 pipeline
+ nop
+ nop
+ eret
+ END(handle_mod)
+ .set at
+
+ .set noreorder
+ LEAF(tlbflush)
+ li t0,PM_4K
+ mtc0 t0,CP0_PAGEMASK
+ la t0,boot_info
+ lw t0,OFFSET_BOOTINFO_TLB_ENTRIES(t0)
+ dmtc0 zero,CP0_ENTRYLO0
+ dmtc0 zero,CP0_ENTRYLO1
+ mfc0 t2,CP0_WIRED
+1: subu t0,1
+ mtc0 t0,CP0_INDEX
+ lui t1,0x0008
+ or t1,t0,t1
+ dsll t1,13
+ dmtc0 t1,CP0_ENTRYHI
+ bne t2,t0,1b
+ tlbwi # delay slot
+ jr ra
+ nop
+ END(tlbflush)
+
+ /*
+ * Code necessary to switch tasks on an Linux/MIPS machine.
+ */
+ .align 5
+ LEAF(resume)
+ /*
+ * Current task's task_struct
+ */
+ lui t5,%hi(current)
+ lw t0,%lo(current)(t5)
+
+ /*
+ * Save status register
+ */
+ mfc0 t1,CP0_STATUS
+ addu t0,a1 # Add tss offset
+ sw t1,TOFF_CP0_STATUS(t0)
+
+ /*
+ * Disable interrupts
+ */
+ ori t2,t1,0x1f
+ xori t2,0x1e
+ mtc0 t2,CP0_STATUS
+
+ /*
+ * Save non-scratch registers
+ * All other registers have been saved on the kernel stack
+ */
+ sw s0,TOFF_REG16(t0)
+ sw s1,TOFF_REG17(t0)
+ sw s2,TOFF_REG18(t0)
+ sw s3,TOFF_REG19(t0)
+ sw s4,TOFF_REG20(t0)
+ sw s5,TOFF_REG21(t0)
+ sw s6,TOFF_REG22(t0)
+ sw s7,TOFF_REG23(t0)
+ sw gp,TOFF_REG28(t0)
+ sw sp,TOFF_REG29(t0)
+ sw fp,TOFF_REG30(t0)
+
+ /*
+ * Save floating point state
+ */
+ sll t2,t1,2
+ bgez t2,2f
+ sw ra,TOFF_REG31(t0) # delay slot
+ sll t2,t1,5
+ bgez t2,1f
+ sdc1 $f0,(TOFF_FPU+0)(t0) # delay slot
+ /*
+ * Store the 16 odd double precision registers
+ */
+ sdc1 $f1,(TOFF_FPU+8)(t0)
+ sdc1 $f3,(TOFF_FPU+24)(t0)
+ sdc1 $f5,(TOFF_FPU+40)(t0)
+ sdc1 $f7,(TOFF_FPU+56)(t0)
+ sdc1 $f9,(TOFF_FPU+72)(t0)
+ sdc1 $f11,(TOFF_FPU+88)(t0)
+ sdc1 $f13,(TOFF_FPU+104)(t0)
+ sdc1 $f15,(TOFF_FPU+120)(t0)
+ sdc1 $f17,(TOFF_FPU+136)(t0)
+ sdc1 $f19,(TOFF_FPU+152)(t0)
+ sdc1 $f21,(TOFF_FPU+168)(t0)
+ sdc1 $f23,(TOFF_FPU+184)(t0)
+ sdc1 $f25,(TOFF_FPU+200)(t0)
+ sdc1 $f27,(TOFF_FPU+216)(t0)
+ sdc1 $f29,(TOFF_FPU+232)(t0)
+ sdc1 $f31,(TOFF_FPU+248)(t0)
+
+ /*
+ * Store the 16 even double precision registers
+ */
+1: cfc1 t1,$31
+ sdc1 $f2,(TOFF_FPU+16)(t0)
+ sdc1 $f4,(TOFF_FPU+32)(t0)
+ sdc1 $f6,(TOFF_FPU+48)(t0)
+ sdc1 $f8,(TOFF_FPU+64)(t0)
+ sdc1 $f10,(TOFF_FPU+80)(t0)
+ sdc1 $f12,(TOFF_FPU+96)(t0)
+ sdc1 $f14,(TOFF_FPU+112)(t0)
+ sdc1 $f16,(TOFF_FPU+128)(t0)
+ sdc1 $f18,(TOFF_FPU+144)(t0)
+ sdc1 $f20,(TOFF_FPU+160)(t0)
+ sdc1 $f22,(TOFF_FPU+176)(t0)
+ sdc1 $f24,(TOFF_FPU+192)(t0)
+ sdc1 $f26,(TOFF_FPU+208)(t0)
+ sdc1 $f28,(TOFF_FPU+224)(t0)
+ sdc1 $f30,(TOFF_FPU+240)(t0)
+ sw t1,(TOFF_FPU+256)(t0)
+
+ /*
+ * Switch current task
+ */
+2: sw a0,%lo(current)(t5)
+ addu a0,a1 # Add tss offset
+
+ /*
+ * Switch address space
+ */
+
+ /*
+ * (Choose new ASID for process)
+ * This isn't really required, but would speed up
+ * context switching.
+ */
+
+ /*
+ * Switch the root pointer
+ */
+ lw t0,TOFF_PG_DIR(a0)
+ li t1,TLB_ROOT
+ mtc0 t1,CP0_ENTRYHI
+ mtc0 zero,CP0_INDEX
+ srl t0,6
+ ori t0,MODE_ALIAS
+ mtc0 t0,CP0_ENTRYLO0
+ mtc0 zero,CP0_ENTRYLO1
+ lw a2,TOFF_CP0_STATUS(a0)
+
+ /*
+ * Flush tlb
+ * (probably not needed, doesn't clobber a0-a3)
+ */
+ jal tlbflush
+ tlbwi # delay slot
+
+ /*
+ * Restore fpu state:
+ * - cp0 status register bits
+ * - fp gp registers
+ * - cp1 status/control register
+ */
+ ori t1,a2,1 # pipeline magic
+ xori t1,1
+ mtc0 t1,CP0_STATUS
+ sll t0,a2,2
+ bgez t0,2f
+ sll t0,a2,5 # delay slot
+ bgez t0,1f
+ ldc1 $f0,(TOFF_FPU+0)(a0) # delay slot
+ /*
+ * Restore the 16 odd double precision registers only
+ * when enabled in the cp0 status register.
+ */
+ ldc1 $f1,(TOFF_FPU+8)(a0)
+ ldc1 $f3,(TOFF_FPU+24)(a0)
+ ldc1 $f5,(TOFF_FPU+40)(a0)
+ ldc1 $f7,(TOFF_FPU+56)(a0)
+ ldc1 $f9,(TOFF_FPU+72)(a0)
+ ldc1 $f11,(TOFF_FPU+88)(a0)
+ ldc1 $f13,(TOFF_FPU+104)(a0)
+ ldc1 $f15,(TOFF_FPU+120)(a0)
+ ldc1 $f17,(TOFF_FPU+136)(a0)
+ ldc1 $f19,(TOFF_FPU+152)(a0)
+ ldc1 $f21,(TOFF_FPU+168)(a0)
+ ldc1 $f23,(TOFF_FPU+184)(a0)
+ ldc1 $f25,(TOFF_FPU+200)(a0)
+ ldc1 $f27,(TOFF_FPU+216)(a0)
+ ldc1 $f29,(TOFF_FPU+232)(a0)
+ ldc1 $f31,(TOFF_FPU+248)(a0)
+
+ /*
+ * Restore the 16 even double precision registers
+ * when cp1 was enabled in the cp0 status register.
+ */
+1: lw t0,(TOFF_FPU+256)(a0)
+ ldc1 $f2,(TOFF_FPU+16)(a0)
+ ldc1 $f4,(TOFF_FPU+32)(a0)
+ ldc1 $f6,(TOFF_FPU+48)(a0)
+ ldc1 $f8,(TOFF_FPU+64)(a0)
+ ldc1 $f10,(TOFF_FPU+80)(a0)
+ ldc1 $f12,(TOFF_FPU+96)(a0)
+ ldc1 $f14,(TOFF_FPU+112)(a0)
+ ldc1 $f16,(TOFF_FPU+128)(a0)
+ ldc1 $f18,(TOFF_FPU+144)(a0)
+ ldc1 $f20,(TOFF_FPU+160)(a0)
+ ldc1 $f22,(TOFF_FPU+176)(a0)
+ ldc1 $f24,(TOFF_FPU+192)(a0)
+ ldc1 $f26,(TOFF_FPU+208)(a0)
+ ldc1 $f28,(TOFF_FPU+224)(a0)
+ ldc1 $f30,(TOFF_FPU+240)(a0)
+ ctc1 t0,$31
+
+ /*
+ * Restore non-scratch registers
+ */
+2: lw s0,TOFF_REG16(a0)
+ lw s1,TOFF_REG17(a0)
+ lw s2,TOFF_REG18(a0)
+ lw s3,TOFF_REG19(a0)
+ lw s4,TOFF_REG20(a0)
+ lw s5,TOFF_REG21(a0)
+ lw s6,TOFF_REG22(a0)
+ lw s7,TOFF_REG23(a0)
+ lw gp,TOFF_REG28(a0)
+ lw sp,TOFF_REG29(a0)
+ lw fp,TOFF_REG30(a0)
+ lw ra,TOFF_REG31(a0)
+
+ /*
+ * Restore status register
+ */
+ lw t0,TOFF_KSP(a0)
+ sw t0,kernelsp
+
+ jr ra
+ mtc0 a2,CP0_STATUS # delay slot
+ END(resume)
+
+/*
+ * Some bits in the config register
+ */
+#define CONFIG_DB (1<<4)
+#define CONFIG_IB (1<<5)
+
+/*
+ * Flush instruction/data caches
+ *
+ * Parameters: a0 - starting address to flush
+ * a1 - size of area to be flushed
+ * a2 - which caches to be flushed
+ *
+ * FIXME: - ignores parameters in a0/a1
+ * - doesn't know about second level caches
+ */
+ .set noreorder
+ LEAF(sys_cacheflush)
+ andi t1,a2,DCACHE
+ beqz t1,do_icache
+ li t0,KSEG0 # delay slot
+
+ /*
+ * Writeback data cache, even lines
+ */
+ li t1,CACHELINES-1
+1: cache Index_Writeback_Inv_D,0(t0)
+ cache Index_Writeback_Inv_D,32(t0)
+ cache Index_Writeback_Inv_D,64(t0)
+ cache Index_Writeback_Inv_D,96(t0)
+ cache Index_Writeback_Inv_D,128(t0)
+ cache Index_Writeback_Inv_D,160(t0)
+ cache Index_Writeback_Inv_D,192(t0)
+ cache Index_Writeback_Inv_D,224(t0)
+ cache Index_Writeback_Inv_D,256(t0)
+ cache Index_Writeback_Inv_D,288(t0)
+ cache Index_Writeback_Inv_D,320(t0)
+ cache Index_Writeback_Inv_D,352(t0)
+ cache Index_Writeback_Inv_D,384(t0)
+ cache Index_Writeback_Inv_D,416(t0)
+ cache Index_Writeback_Inv_D,448(t0)
+ cache Index_Writeback_Inv_D,480(t0)
+ addiu t0,512
+ bnez t1,1b
+ subu t1,1
+
+ /*
+ * Writeback data cache, odd lines
+ * Only needed for 16 byte line size
+ */
+ mfc0 t1,CP0_CONFIG
+ andi t1,CONFIG_DB
+ bnez t1,do_icache
+ li t1,CACHELINES-1
+1: cache Index_Writeback_Inv_D,16(t0)
+ cache Index_Writeback_Inv_D,48(t0)
+ cache Index_Writeback_Inv_D,80(t0)
+ cache Index_Writeback_Inv_D,112(t0)
+ cache Index_Writeback_Inv_D,144(t0)
+ cache Index_Writeback_Inv_D,176(t0)
+ cache Index_Writeback_Inv_D,208(t0)
+ cache Index_Writeback_Inv_D,240(t0)
+ cache Index_Writeback_Inv_D,272(t0)
+ cache Index_Writeback_Inv_D,304(t0)
+ cache Index_Writeback_Inv_D,336(t0)
+ cache Index_Writeback_Inv_D,368(t0)
+ cache Index_Writeback_Inv_D,400(t0)
+ cache Index_Writeback_Inv_D,432(t0)
+ cache Index_Writeback_Inv_D,464(t0)
+ cache Index_Writeback_Inv_D,496(t0)
+ addiu t0,512
+ bnez t1,1b
+ subu t1,1
+
+do_icache: andi t1,a2,ICACHE
+ beqz t1,done
+
+ /*
+ * Flush instruction cache, even lines
+ */
+ lui t0,0x8000
+ li t1,CACHELINES-1
+1: cache Index_Invalidate_I,0(t0)
+ cache Index_Invalidate_I,32(t0)
+ cache Index_Invalidate_I,64(t0)
+ cache Index_Invalidate_I,96(t0)
+ cache Index_Invalidate_I,128(t0)
+ cache Index_Invalidate_I,160(t0)
+ cache Index_Invalidate_I,192(t0)
+ cache Index_Invalidate_I,224(t0)
+ cache Index_Invalidate_I,256(t0)
+ cache Index_Invalidate_I,288(t0)
+ cache Index_Invalidate_I,320(t0)
+ cache Index_Invalidate_I,352(t0)
+ cache Index_Invalidate_I,384(t0)
+ cache Index_Invalidate_I,416(t0)
+ cache Index_Invalidate_I,448(t0)
+ cache Index_Invalidate_I,480(t0)
+ addiu t0,512
+ bnez t1,1b
+ subu t1,1
+
+ /*
+ * Flush instruction cache, even lines
+ * Only needed for 16 byte line size
+ */
+ mfc0 t1,CP0_CONFIG
+ andi t1,CONFIG_IB
+ bnez t1,done
+ li t1,CACHELINES-1
+1: cache Index_Invalidate_I,16(t0)
+ cache Index_Invalidate_I,48(t0)
+ cache Index_Invalidate_I,80(t0)
+ cache Index_Invalidate_I,112(t0)
+ cache Index_Invalidate_I,144(t0)
+ cache Index_Invalidate_I,176(t0)
+ cache Index_Invalidate_I,208(t0)
+ cache Index_Invalidate_I,240(t0)
+ cache Index_Invalidate_I,272(t0)
+ cache Index_Invalidate_I,304(t0)
+ cache Index_Invalidate_I,336(t0)
+ cache Index_Invalidate_I,368(t0)
+ cache Index_Invalidate_I,400(t0)
+ cache Index_Invalidate_I,432(t0)
+ cache Index_Invalidate_I,464(t0)
+ cache Index_Invalidate_I,496(t0)
+ addiu t0,512
+ bnez t1,1b
+ subu t1,1
+
+done: j ra
+ nop
+ END(sys_cacheflush)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
new file mode 100644
index 000000000..f5037fbd7
--- /dev/null
+++ b/arch/mips/kernel/setup.c
@@ -0,0 +1,207 @@
+/*
+ * linux/arch/mips/kernel/setup.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ * Copyright (C) 1995 Ralf Baechle
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/ldt.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+
+#include <asm/asm.h>
+#include <asm/bootinfo.h>
+#include <asm/vector.h>
+#include <asm/segment.h>
+#include <asm/stackframe.h>
+#include <asm/system.h>
+
+/*
+ * How to handle the machine's features
+ */
+struct feature *feature;
+
+#ifdef CONFIG_ACER_PICA_61
+void acer_pica_61_handle_int(void);
+struct feature acer_pica_61_feature = {
+ acer_pica_61_handle_int
+};
+#endif
+#ifdef CONFIG_DECSTATION
+void decstation_handle_handle_int(void);
+struct feature decstation_feature = {
+ decstation_handle_handle_int
+};
+#endif
+#ifdef CONFIG_DESKSTATION_RPC44
+void deskstation_rpc44_handle_int(void);
+struct feature deskstation_rpc44_feature = {
+ deskstation_rpc44_handle_int
+};
+#endif
+#ifdef CONFIG_DESKSTATION_TYNE
+void deskstation_tyne_handle_int(void);
+struct feature deskstation_tyne_feature = {
+ deskstation_tyne_handle_int
+};
+#endif
+#ifdef CONFIG_MIPS_MAGNUM_4000
+void mips_magnum_4000_handle_int(void);
+struct feature mips_magnum_4000_feature = {
+ mips_magnum_4000_handle_int
+};
+#endif
+
+/*
+ * Tell us the machine setup..
+ */
+char wait_available; /* set if the "wait" instruction available */
+
+/*
+ * Bus types ..
+ */
+int EISA_bus = 0;
+
+/*
+ * Setup options
+ */
+struct drive_info_struct drive_info;
+struct screen_info screen_info = SCREEN_INFO;
+
+unsigned char aux_device_present;
+extern int ramdisk_size;
+extern int root_mountflags;
+extern int _end;
+
+extern char empty_zero_page[PAGE_SIZE];
+
+/*
+ * Initialise this structure so that it will be placed in the
+ * .data section of the object file
+ */
+struct bootinfo boot_info = BOOT_INFO;
+
+/*
+ * This is set up by the setup-routine at boot-time
+ */
+#define PARAM empty_zero_page
+#if 0
+#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))
+#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))
+#endif
+
+static char command_line[CL_SIZE] = { 0, };
+
+#if 0
+/*
+ * Code for easy access to new style bootinfo
+ *
+ * Parameter: tag -- taglist entry
+ *
+ * returns : (tag *) -- pointer to taglist entry, NULL for not found
+ */
+tag *
+bi_TagFind(enum bi_tag tag)
+{
+ /* TBD */
+ return 0;
+}
+
+/*
+ * Only for taglist creators (bootloaders)
+ *
+ * Parameter: tag -- (enum bi_tag) taglist entry
+ *
+ * returns : 1 -- success
+ * 0 -- failure
+ */
+int
+bi_TagAdd(enum bi_tag tag, unsigned long size, void *tagdata)
+{
+ /* TBD */
+ return 0;
+}
+#endif /* 0 */
+
+void setup_arch(char **cmdline_p,
+ unsigned long * memory_start_p, unsigned long * memory_end_p)
+{
+ unsigned long memory_start, memory_end;
+
+ switch(boot_info.machtype)
+ {
+#ifdef CONFIG_ACER_PICA_61
+ case MACH_ACER_PICA_61:
+ feature = &acer_pica_61_feature;
+ break;
+#endif
+#ifdef CONFIG_DECSTATION
+ case MACH_DECSTATION:
+ feature = &decstation_feature;
+ break;
+#endif
+#ifdef CONFIG_DESKSTATION_RPC
+ case MACH_DESKSTATION_RPC:
+ feature = &deskstation_rpc44_feature;
+ break;
+#endif
+#ifdef CONFIG_DESKSTATION_TYNE
+ case MACH_DESKSTATION_TYNE:
+ feature = &deskstation_tyne_feature;
+ break;
+#endif
+#ifdef CONFIG_MIPS_MAGNUM_4000
+ case MACH_MIPS_MAGNUM_4000:
+ feature = &mips_magnum_4000_feature;
+ break;
+#endif
+ default:
+ panic("Unsupported architecture");
+ }
+
+#if 0
+ ROOT_DEV = ORIG_ROOT_DEV;
+#else
+ ROOT_DEV = 0x021c; /* fd0H1440 */
+/* ROOT_DEV = 0x0101; */ /* ram */
+/* ROOT_DEV = 0x00ff; */ /* NFS */
+#endif
+ memcpy(&drive_info, &boot_info.drive_info, sizeof(drive_info));
+#if 0
+ aux_device_present = AUX_DEVICE_INFO;
+#endif
+ memory_end = boot_info.memupper;
+ memory_end &= PAGE_MASK;
+ ramdisk_size = boot_info.ramdisk_size;
+ if (boot_info.mount_root_rdonly)
+ root_mountflags |= MS_RDONLY;
+
+ memory_start = (unsigned long) &_end;
+ memory_start += (ramdisk_size << 10);
+
+ *cmdline_p = command_line;
+ *memory_start_p = memory_start;
+ *memory_end_p = memory_end;
+
+#if 0
+ /*
+ * Check that struct pt_regs is defined properly
+ * (Should be optimized away, but gcc 2.6.3 is too bad..)
+ */
+ if (FR_SIZE != sizeof(struct pt_regs) ||
+ FR_SIZE & 7)
+ {
+ panic("Check_definition_of_struct_pt_regs\n");
+ }
+#endif
+}
diff --git a/arch/mips/signal.c b/arch/mips/kernel/signal.c
index ef3246ee0..ea00551a9 100644
--- a/arch/mips/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -1,10 +1,11 @@
/*
- * linux/kernel/signal.c
+ * linux/arch/mips/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#include <linux/sched.h>
+#include <linux/mm.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
@@ -19,63 +20,7 @@
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
-asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs);
-
-asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset)
-{
- sigset_t new_set, old_set = current->blocked;
- int error;
-
- if (set) {
- error = verify_area(VERIFY_READ, set, sizeof(sigset_t));
- if (error)
- return error;
- new_set = get_fs_long((unsigned long *) set) & _BLOCKABLE;
- switch (how) {
- case SIG_BLOCK:
- current->blocked |= new_set;
- break;
- case SIG_UNBLOCK:
- current->blocked &= ~new_set;
- break;
- case SIG_SETMASK:
- current->blocked = new_set;
- break;
- default:
- return -EINVAL;
- }
- }
- if (oset) {
- error = verify_area(VERIFY_WRITE, oset, sizeof(sigset_t));
- if (error)
- return error;
- put_fs_long(old_set, (unsigned long *) oset);
- }
- return 0;
-}
-
-asmlinkage int sys_sgetmask(void)
-{
- return current->blocked;
-}
-
-asmlinkage int sys_ssetmask(int newmask)
-{
- int old=current->blocked;
-
- current->blocked = newmask & _BLOCKABLE;
- return old;
-}
-
-asmlinkage int sys_sigpending(sigset_t *set)
-{
- int error;
- /* fill in "set" with signals pending but blocked. */
- error = verify_area(VERIFY_WRITE, set, 4);
- if (!error)
- put_fs_long(current->blocked & current->signal, (unsigned long *)set);
- return error;
-}
+asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
/*
* atomically swap in the new signal mask, and wait for a signal.
@@ -87,11 +32,7 @@ asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long
mask = current->blocked;
current->blocked = set & _BLOCKABLE;
-#if defined (__i386__)
- regs->eax = -EINTR;
-#elif defined (__mips__)
regs->reg2 = -EINTR;
-#endif
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
@@ -101,99 +42,6 @@ asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long
}
/*
- * POSIX 3.3.1.3:
- * "Setting a signal action to SIG_IGN for a signal that is pending
- * shall cause the pending signal to be discarded, whether or not
- * it is blocked" (but SIGCHLD is unspecified: linux leaves it alone).
- *
- * "Setting a signal action to SIG_DFL for a signal that is pending
- * and whose default action is to ignore the signal (for example,
- * SIGCHLD), shall cause the pending signal to be discarded, whether
- * or not it is blocked"
- *
- * Note the silly behaviour of SIGCHLD: SIG_IGN means that the signal
- * isn't actually ignored, but does automatic child reaping, while
- * SIG_DFL is explicitly said by POSIX to force the signal to be ignored..
- */
-static void check_pending(int signum)
-{
- struct sigaction *p;
-
- p = signum - 1 + current->sigaction;
- if (p->sa_handler == SIG_IGN) {
- if (signum == SIGCHLD)
- return;
- current->signal &= ~_S(signum);
- return;
- }
- if (p->sa_handler == SIG_DFL) {
- if (signum != SIGCONT && signum != SIGCHLD && signum != SIGWINCH)
- return;
- current->signal &= ~_S(signum);
- return;
- }
-}
-
-asmlinkage int sys_signal(int signum, unsigned long handler)
-{
- struct sigaction tmp;
-
- if (signum<1 || signum>32)
- return -EINVAL;
- if (signum==SIGKILL || signum==SIGSTOP)
- return -EINVAL;
- if (handler >= TASK_SIZE)
- return -EFAULT;
- tmp.sa_handler = (void (*)(int)) handler;
- tmp.sa_mask = 0;
- tmp.sa_flags = SA_ONESHOT | SA_NOMASK;
- tmp.sa_restorer = NULL;
- handler = (long) current->sigaction[signum-1].sa_handler;
- current->sigaction[signum-1] = tmp;
- check_pending(signum);
- return handler;
-}
-
-asmlinkage int sys_sigaction(int signum, const struct sigaction * action,
- struct sigaction * oldaction)
-{
- struct sigaction new_sa, *p;
-
- if (signum<1 || signum>32)
- return -EINVAL;
- if (signum==SIGKILL || signum==SIGSTOP)
- return -EINVAL;
- p = signum - 1 + current->sigaction;
- if (action) {
- int err = verify_area(VERIFY_READ, action, sizeof(*action));
- if (err)
- return err;
- memcpy_fromfs(&new_sa, action, sizeof(struct sigaction));
- if (new_sa.sa_flags & SA_NOMASK)
- new_sa.sa_mask = 0;
- else {
- new_sa.sa_mask |= _S(signum);
- new_sa.sa_mask &= _BLOCKABLE;
- }
- if (TASK_SIZE <= (unsigned long) new_sa.sa_handler)
- return -EFAULT;
- }
- if (oldaction) {
- int err = verify_area(VERIFY_WRITE, oldaction, sizeof(*oldaction));
- if (err)
- return err;
- memcpy_tofs(oldaction, p, sizeof(struct sigaction));
- }
- if (action) {
- *p = new_sa;
- check_pending(signum);
- }
- return 0;
-}
-
-asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
-
-/*
* This sets regs->reg29 even though we don't actually use sigstacks yet..
*/
asmlinkage int sys_sigreturn(unsigned long __unused)
@@ -221,9 +69,25 @@ asmlinkage int sys_sigreturn(unsigned long __unused)
regs->reg13 = context.sc_t5;
regs->reg14 = context.sc_t6;
regs->reg15 = context.sc_t7;
+ regs->reg16 = context.sc_s0;
+ regs->reg17 = context.sc_s1;
+ regs->reg18 = context.sc_s2;
+ regs->reg19 = context.sc_s3;
+ regs->reg20 = context.sc_s4;
+ regs->reg21 = context.sc_s5;
+ regs->reg22 = context.sc_s6;
+ regs->reg23 = context.sc_s7;
regs->reg24 = context.sc_t8;
regs->reg25 = context.sc_t9;
+ /*
+ * Skip k0/k1
+ */
+ regs->reg28 = context.sc_gp;
regs->reg29 = context.sc_sp;
+ regs->reg30 = context.sc_fp;
+ regs->reg31 = context.sc_ra;
+ regs->cp0_epc = context.sc_epc;
+ regs->cp0_cause = context.sc_cause;
/*
* disable syscall checks
@@ -244,11 +108,11 @@ static void setup_frame(struct sigaction * sa, unsigned long ** fp,
unsigned long * frame;
frame = *fp;
- frame -= 21;
+ frame -= 32;
if (verify_area(VERIFY_WRITE,frame,21*4))
do_exit(SIGSEGV);
/*
- * set up the "normal" stack seen by the signal handler (iBCS2)
+ * set up the "normal" stack seen by the signal handler
*/
put_fs_long(regs->reg1 , frame );
put_fs_long(regs->reg2 , frame+ 1);
@@ -258,34 +122,49 @@ static void setup_frame(struct sigaction * sa, unsigned long ** fp,
put_fs_long(regs->reg6 , frame+ 5);
put_fs_long(regs->reg7 , frame+ 6);
put_fs_long(regs->reg8 , frame+ 7);
- put_fs_long(regs->reg10, frame+ 8);
- put_fs_long(regs->reg11, frame+ 9);
- put_fs_long(regs->reg12, frame+10);
- put_fs_long(regs->reg13, frame+11);
- put_fs_long(regs->reg14, frame+12);
- put_fs_long(regs->reg15, frame+13);
- put_fs_long(regs->reg16, frame+14);
- put_fs_long(regs->reg17, frame+15);
- put_fs_long(regs->reg24, frame+16);
- put_fs_long(regs->reg25, frame+17);
- put_fs_long(regs->reg29, frame+18);
- put_fs_long(pc , frame+19);
- put_fs_long(oldmask , frame+20);
+ put_fs_long(regs->reg9 , frame+ 8);
+ put_fs_long(regs->reg10, frame+ 9);
+ put_fs_long(regs->reg11, frame+10);
+ put_fs_long(regs->reg12, frame+11);
+ put_fs_long(regs->reg13, frame+12);
+ put_fs_long(regs->reg14, frame+13);
+ put_fs_long(regs->reg15, frame+14);
+ put_fs_long(regs->reg16, frame+15);
+ put_fs_long(regs->reg17, frame+16);
+ put_fs_long(regs->reg18, frame+17);
+ put_fs_long(regs->reg19, frame+18);
+ put_fs_long(regs->reg20, frame+19);
+ put_fs_long(regs->reg21, frame+20);
+ put_fs_long(regs->reg22, frame+21);
+ put_fs_long(regs->reg23, frame+22);
+ put_fs_long(regs->reg24, frame+23);
+ put_fs_long(regs->reg25, frame+24);
+ /*
+ * Don't copy k0/k1
+ */
+ put_fs_long(regs->reg28, frame+25);
+ put_fs_long(regs->reg29, frame+26);
+ put_fs_long(regs->reg30, frame+27);
+ put_fs_long(regs->reg31, frame+28);
+ put_fs_long(pc , frame+29);
+ put_fs_long(oldmask , frame+30);
/*
* set up the return code...
*
+ * .set noreorder
* .set noat
* syscall
- * li $1,__NR_sigreturn
+ * li v0,__NR_sigreturn
* .set at
+ * .set reorder
*/
- put_fs_long(0x24010077, frame+20); /* li $1,119 */
- put_fs_long(0x000000c0, frame+21); /* syscall */
+ put_fs_long(0x24020077, frame+31); /* li $2,119 */
+ put_fs_long(0x000000c0, frame+32); /* syscall */
*fp = frame;
/*
* Flush caches so the instructions will be correctly executed.
*/
- cacheflush(frame, 21*4, BCACHE);
+ sys_cacheflush(frame, 32*4, BCACHE);
}
/*
@@ -307,30 +186,8 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
struct sigaction * sa;
while ((signr = current->signal & mask)) {
-#if defined (__i386__)
- __asm__("bsf %2,%1\n\t"
- "btrl %1,%0"
- :"=m" (current->signal),"=r" (signr)
- :"1" (signr));
-#elif defined (__mips__)
- __asm__(".set\tnoreorder\n\t"
- ".set\tnoat\n\t"
- "li\t%1,1\n"
- "1:\tand\t$1,%2,%1\n\t"
- "beq\t$0,$1,2f\n\t"
- "sll\t%2,%2,1\n\t"
- "bne\t$0,%2,1b\n\t"
- "add\t%0,%0,1\n"
- "2:\tli\t%2,-2\n\t"
- "sllv\t%2,%2,%0\n\t"
- "and\t%1,%1,%2\n\t"
- ".set\tat\n\t"
- ".set\treorder\n"
- "2:\n\t"
- :"=r" (signr),"=r" (current->signal),"=r" (mask)
- :"0" (signr),"1" (current->signal)
- :"$1");
-#endif
+ signr = ffz(~signr);
+ clear_bit(signr, &current->signal);
sa = current->sigaction + signr;
signr++;
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
@@ -376,7 +233,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
continue;
case SIGQUIT: case SIGILL: case SIGTRAP:
- case SIGIOT: case SIGFPE: case SIGSEGV:
+ case SIGIOT: case SIGFPE: case SIGSEGV: case SIGBUS:
if (current->binfmt && current->binfmt->core_dump) {
if (current->binfmt->core_dump(signr, regs))
signr |= 0x80;
@@ -404,7 +261,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
regs->reg2 == -ERESTARTSYS ||
regs->reg2 == -ERESTARTNOINTR)) {
regs->reg2 = regs->orig_reg2;
- regs->cp0_epc -= 2;
+ regs->cp0_epc -= 4;
}
if (!handler_signal) /* no handler will be called - return 0 */
return 0;
@@ -425,16 +282,14 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
* force a kernel-mode page-in of the signal
* handler to reduce races
*/
- __asm__(".set\tnoat\n\t"
- "lwu\t$1,(%0)\n\t"
- ".set\tat\n\t"
- :
- :"r" ((char *) pc)
- :"$1");
+ __asm__("lw\t$0,(%0)"
+ : /* no output */
+ :"r" ((char *) pc));
current->blocked |= sa->sa_mask;
oldmask |= sa->sa_mask;
}
regs->reg29 = (unsigned long) frame;
regs->cp0_epc = pc; /* "return" to the first handler */
+
return 1;
}
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
new file mode 100644
index 000000000..36e8a31e8
--- /dev/null
+++ b/arch/mips/kernel/traps.c
@@ -0,0 +1,438 @@
+/*
+ * arch/mips/kernel/traps.c
+ *
+ * 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.
+ */
+
+/*
+ * 'traps.c' handles hardware traps and faults after we have saved some
+ * state in 'asm.s'. Currently mostly a debugging-aid, will be extended
+ * to mainly kill the offending process (probably by giving it a signal,
+ * but possibly by killing it outright if necessary).
+ *
+ * FIXME: This is the place for a fpu emulator.
+ */
+#include <linux/head.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/config.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+
+#include <asm/vector.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/mipsregs.h>
+#include <asm/bootinfo.h>
+
+static inline void console_verbose(void)
+{
+ extern int console_loglevel;
+ console_loglevel = 15;
+}
+
+/*
+ * Machine specific interrupt handlers
+ */
+extern asmlinkage void acer_pica_61_handle_int(void);
+extern asmlinkage void decstation_handle_int(void);
+extern asmlinkage void deskstation_rpc44_handle_int(void);
+extern asmlinkage void deskstation_tyne_handle_int(void);
+extern asmlinkage void mips_magnum_4000_handle_int(void);
+
+extern asmlinkage void handle_mod(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_vcei(void);
+extern asmlinkage void handle_fpe(void);
+extern asmlinkage void handle_vced(void);
+extern asmlinkage void handle_watch(void);
+extern asmlinkage void handle_reserved(void);
+
+static char *cpu_names[] = CPU_NAMES;
+
+/*
+ * Fix address errors. This is slow, so try not to use it. This is
+ * disabled by default, anyway.
+ */
+int fix_ade_enabled = 0;
+unsigned long page_colour_mask;
+
+int kstack_depth_to_print = 24;
+
+/*
+ * 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)
+
+void die_if_kernel(char * str, struct pt_regs * regs, long err)
+{
+ int i;
+ int *stack;
+ u32 *sp, *pc, addr, module_start, module_end;
+ extern char start_kernel, _etext;
+
+ if ((regs->cp0_status & (ST0_ERL|ST0_EXL)) == 0)
+ return;
+
+ sp = (u32 *)regs->reg29;
+ pc = (u32 *)regs->cp0_epc;
+
+ console_verbose();
+ printk("%s: %08lx\n", str, err );
+
+ show_regs(regs);
+
+ /*
+ * Some goodies...
+ */
+ printk("Int : %ld\n", regs->interrupt);
+
+ /*
+ * Dump the stack
+ */
+ if (STACK_MAGIC != *(u32 *)current->kernel_stack_page)
+ printk("Corrupted stack page\n");
+ printk("Process %s (pid: %d, stackpage=%08lx)\nStack: ",
+ current->comm, current->pid, current->kernel_stack_page);
+ for(i=0;i<5;i++)
+ printk("%08x ", *sp++);
+ stack = (int *) sp;
+ for(i=0; i < kstack_depth_to_print; i++) {
+ if (((u32) stack & (PAGE_SIZE -1)) == 0)
+ break;
+ if (i && ((i % 8) == 0))
+ printk("\n ");
+ printk("%08lx ", get_user_long(stack++));
+ }
+ printk("\nCall Trace: ");
+ stack = (int *)sp;
+ i = 1;
+ module_start = VMALLOC_START;
+ module_end = module_start + MODULE_RANGE;
+ while (((u32)stack & (PAGE_SIZE -1)) != 0) {
+ addr = get_user_long(stack++);
+ /*
+ * If the address is either in the text segment of the
+ * kernel, or in the region which contains vmalloc'ed
+ * memory, it *may* be the address of a calling
+ * routine; if so, print it so that someone tracing
+ * down the cause of the crash will be able to figure
+ * out the call path that was taken.
+ */
+ if (((addr >= (u32) &start_kernel) &&
+ (addr <= (u32) &_etext)) ||
+ ((addr >= module_start) && (addr <= module_end))) {
+ if (i && ((i % 8) == 0))
+ printk("\n ");
+ printk("%08x ", addr);
+ i++;
+ }
+ }
+
+ printk("\nCode : ");
+ for(i=0;i<5;i++)
+ printk("%08x ", *pc++);
+ printk("\n");
+ do_exit(SIGSEGV);
+}
+
+static void
+fix_ade(struct pt_regs *regs, int write)
+{
+ printk("Received address error (ade%c)\n", write ? 's' : 'l');
+ panic("Fixing address errors not implemented yet");
+}
+
+void do_adel(struct pt_regs *regs)
+{
+ unsigned long pc = regs->cp0_epc;
+ int i;
+
+ if(fix_ade_enabled)
+ {
+ fix_ade(regs, 0);
+ return;
+ }
+#if 0
+ for(i=0; i<NR_TASKS;i++)
+ if(task[i] && task[i]->pid >= 2)
+ {
+ printk("Process %d\n", task[i]->pid);
+ dump_list_process(task[i], pc);
+ }
+#endif
+ show_regs(regs);
+while(1);
+ dump_tlb_nonwired();
+ send_sig(SIGSEGV, current, 1);
+}
+
+void do_ades(struct pt_regs *regs)
+{
+ unsigned long pc = regs->cp0_epc;
+ int i;
+
+ if(fix_ade_enabled)
+ {
+ fix_ade(regs, 1);
+ return;
+ }
+while(1);
+ for(i=0; i<NR_TASKS;i++)
+ if(task[i] && task[i]->pid >= 2)
+ {
+ printk("Process %d\n", task[i]->pid);
+ dump_list_process(task[i], pc);
+ }
+ show_regs(regs);
+ dump_tlb_nonwired();
+ send_sig(SIGSEGV, current, 1);
+}
+
+/*
+ * The ibe/dbe exceptions are signaled by onboard hardware and should get
+ * a board specific handlers to get maximum available information. Bus
+ * errors are always symptom of hardware malfunction or a kernel error.
+ *
+ * FIXME: Linux/68k sends a SIGSEGV for a buserror which seems to be wrong.
+ * This is certainly wrong. Actually, all hardware errors (ades,adel,ibe,dbe)
+ * are bus errors and therefor should send a SIGBUS! (Andy)
+ */
+void do_ibe(struct pt_regs *regs)
+{
+while(1);
+ send_sig(SIGBUS, current, 1);
+}
+
+void do_dbe(struct pt_regs *regs)
+{
+while(1);
+ send_sig(SIGBUS, current, 1);
+}
+
+void do_ov(struct pt_regs *regs)
+{
+while(1);
+ send_sig(SIGFPE, current, 1);
+}
+
+void do_fpe(struct pt_regs *regs)
+{
+while(1);
+ send_sig(SIGFPE, current, 1);
+}
+
+void do_bp(struct pt_regs *regs)
+{
+while(1);
+ send_sig(SIGILL, current, 1);
+}
+
+void do_tr(struct pt_regs *regs)
+{
+while(1);
+ send_sig(SIGILL, current, 1);
+}
+
+void do_ri(struct pt_regs *regs)
+{
+ int i;
+
+ for(i=0; i<NR_TASKS;i++)
+ if(task[i] && task[i]->pid >= 2)
+ {
+ printk("Process %d\n", task[i]->pid);
+ dump_list_process(task[i], 0x7ffff000);
+ }
+ show_regs(regs);
+while(1);
+ send_sig(SIGILL, current, 1);
+}
+
+void do_cpu(struct pt_regs *regs)
+{
+ unsigned int cpid;
+
+ cpid = (regs->cp0_cause >> CAUSEB_CE) & 3;
+ switch(cpid)
+ {
+ case 1:
+ regs->cp0_status |= ST0_CU1;
+ break;
+ case 3:
+ /*
+ * This is a guess how to handle MIPS IV -
+ * I don't have a manual.
+ */
+ if((boot_info.cputype == CPU_R8000) ||
+ (boot_info.cputype == CPU_R10000))
+ {
+ regs->cp0_status |= ST0_CU3;
+ break;
+ }
+ case 0:
+ /*
+ * CPU for cp0 can only happen in user mode
+ */
+ case 2:
+ send_sig(SIGILL, current, 1);
+ break;
+ }
+}
+
+void do_vcei(struct pt_regs *regs)
+{
+ /*
+ * Only possible on R4[04]00[SM]C. No handler because
+ * I don't have such a cpu.
+ */
+ panic("Caught VCEI exception - can't handle yet\n");
+}
+
+void do_vced(struct pt_regs *regs)
+{
+ /*
+ * Only possible on R4[04]00[SM]C. No handler because
+ * I don't have such a cpu.
+ */
+ panic("Caught VCED exception - can't handle yet\n");
+}
+
+void do_watch(struct pt_regs *regs)
+{
+ panic("Caught WATCH exception - can't handle yet\n");
+}
+
+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.
+ */
+ panic("Caught reserved exception - can't handle.\n");
+}
+
+void trap_init(void)
+{
+ unsigned long i;
+
+ if(boot_info.machtype == MACH_MIPS_MAGNUM_4000)
+ EISA_bus = 1;
+
+ /*
+ * Setup default vectors
+ */
+ for (i=0;i<=31;i++)
+ set_except_vector(i, handle_reserved);
+
+ /*
+ * Handling the following exceptions depends mostly of the cpu type
+ */
+ switch(boot_info.cputype) {
+ case CPU_R4000MC:
+ case CPU_R4400MC:
+ case CPU_R4000SC:
+ case CPU_R4400SC:
+ /*
+ * Handlers not implemented yet. If should every be used
+ * it's a bug in the Linux/MIPS kernel, anyway.
+ */
+ set_except_vector(14, handle_vcei);
+ set_except_vector(31, handle_vced);
+ case CPU_R4000PC:
+ case CPU_R4400PC:
+ case CPU_R4200:
+ /* case CPU_R4300: */
+ /*
+ * Use watch exception to trap on access to address zero
+ */
+ set_except_vector(23, handle_watch);
+ watch_set(KSEG0, 3);
+ case CPU_R4600:
+ set_except_vector(1, handle_mod);
+ set_except_vector(2, handle_tlbl);
+ set_except_vector(3, handle_tlbs);
+ set_except_vector(4, handle_adel);
+ set_except_vector(5, handle_ades);
+ /*
+ * The following two are signaled by onboard hardware and
+ * should get board specific handlers to get maximum
+ * available information.
+ */
+ 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(15, handle_fpe);
+
+ /*
+ * Compute mask for page_colour(). This is based on the
+ * size of the data cache. Does the size of the icache
+ * need to be accounted for?
+ */
+ i = read_32bit_cp0_register(CP0_CONFIG);
+ i = (i >> 26) & 7;
+ page_colour_mask = 1 << (12 + i);
+ break;
+ case CPU_R2000:
+ case CPU_R3000:
+ case CPU_R3000A:
+ case CPU_R3041:
+ case CPU_R3051:
+ case CPU_R3052:
+ case CPU_R3081:
+ case CPU_R3081E:
+ case CPU_R6000:
+ case CPU_R6000A:
+ case CPU_R8000:
+ printk("Detected unsupported CPU type %s.\n",
+ cpu_names[boot_info.cputype]);
+ panic("Can't handle CPU\n");
+ break;
+
+ /*
+ * The R10000 is in most aspects similar to the R4400. It however
+ * should get some special optimizations.
+ */
+ case CPU_R10000:
+ write_32bit_cp0_register(CP0_FRAMEMASK, 0);
+ panic("CPU too expensive - making holiday in the ANDES!");
+ break;
+ case CPU_UNKNOWN:
+ default:
+ panic("Unknown CPU type");
+ }
+
+ /*
+ * The interrupt handler depends most of the board type.
+ */
+ set_except_vector(0, feature->handle_int);
+}
diff --git a/arch/mips/kernel/tyne.S b/arch/mips/kernel/tyne.S
new file mode 100644
index 000000000..912f6d414
--- /dev/null
+++ b/arch/mips/kernel/tyne.S
@@ -0,0 +1,114 @@
+/*
+ * arch/mips/kernel/tyne.S
+ *
+ * Deskstation Tyne specific Assembler code
+ *
+ * Copyright (C) 1994, 1995 Waldorf Electronics
+ * written by Ralf Baechle and Andreas Busse
+ */
+#include <asm/asm.h>
+#include <asm/mipsconfig.h>
+#include <asm/mipsregs.h>
+#include <asm/stackframe.h>
+
+/*
+ * Deskstation Tyne interrupt handler
+ */
+ .text
+ .set noreorder
+ .set noat
+ .align 5
+ NESTED(deskstation_tyne_handle_int, FR_SIZE, sp)
+ SAVE_ALL
+ CLI
+ .set at
+ lui s0,%hi(PORT_BASE)
+ li t1,0x0f
+ sb t1,%lo(PORT_BASE+0x20)(s0) # poll command
+ lb t1,%lo(PORT_BASE+0x20)(s0) # read result
+ li s1,1
+ bgtz t1,Lpoll_second
+ andi t1,t1,7
+ /*
+ * Acknowledge first pic
+ */
+ lb t2,%lo(PORT_BASE+0x21)(s0)
+ lui s4,%hi(cache_21)
+ lb t0,%lo(cache_21)(s4)
+ sllv s1,s1,t1
+ or t0,t0,s1
+ sb t0,%lo(cache_21)(s4)
+ sb t0,%lo(PORT_BASE+0x21)(s0)
+ lui s3,%hi(intr_count)
+ lw t0,%lo(intr_count)(s3)
+ li t2,0x20
+ sb t2,%lo(PORT_BASE+0x20)(s0)
+ /*
+ * Now call the real handler
+ */
+ la t3,IRQ_vectors
+ sll t2,t1,2
+ addu t3,t3,t2
+ lw t3,(t3)
+ addiu t0,t0,1
+ jalr t3
+ sw t0,%lo(intr_count)(s3) # delay slot
+ lw t0,%lo(intr_count)(s3)
+ /*
+ * Unblock first pic
+ */
+ lbu t1,%lo(PORT_BASE+0x21)(s0)
+ lb t1,%lo(cache_21)(s4)
+ subu t0,t0,1
+ sw t0,%lo(intr_count)(s3)
+ nor s1,zero,s1
+ and t1,t1,s1
+ sb t1,%lo(cache_21)(s4)
+ jr v0
+ sb t1,%lo(PORT_BASE+0x21)(s0) # delay slot
+
+ .align 5
+Lpoll_second: li t1,0x0f
+ sb t1,%lo(PORT_BASE+0xa0)(s0) # poll command
+ lb t1,%lo(PORT_BASE+0xa0)(s0) # read result
+ lui s4,%hi(cache_A1)
+ bgtz t1,spurious_interrupt
+ andi t1,t1,7
+ /*
+ * Acknowledge second pic
+ */
+ lbu t2,%lo(PORT_BASE+0xa1)(s0)
+ lb t3,%lo(cache_A1)(s4)
+ sllv s1,s1,t1
+ or t3,t3,s1
+ sb t3,%lo(cache_A1)(s4)
+ sb t3,%lo(PORT_BASE+0xa1)(s0)
+ li t3,0x20
+ sb t3,%lo(PORT_BASE+0xa0)(s0)
+ lui s3,%hi(intr_count)
+ lw t0,%lo(intr_count)(s3)
+ sb t3,%lo(PORT_BASE+0x20)(s0)
+ /*
+ * Now call the real handler
+ */
+ la t0,IRQ_vectors
+ sll t2,t1,2
+ addu t0,t0,t2
+ lw t0,32(t0)
+ addiu t0,t0,1
+ jalr t0
+ sw t0,%lo(intr_count)(s3) # delay slot
+ lw t0,%lo(intr_count)(s3)
+ /*
+ * Unblock second pic
+ */
+ lb t1,%lo(PORT_BASE+0xa1)(s0)
+ lb t1,%lo(cache_A1)(s4)
+ subu t0,t0,1
+ lw t0,%lo(intr_count)(s3)
+ nor s1,zero,s1
+ and t1,t1,s1
+ sb t1,%lo(cache_A1)(s4)
+ jr v0
+ sb t1,%lo(PORT_BASE+0xa1)(s0) # delay slot
+ END(deskstation_tyne_handle_int)
diff --git a/arch/mips/kernel/tynedma.c b/arch/mips/kernel/tynedma.c
new file mode 100644
index 000000000..04846cddd
--- /dev/null
+++ b/arch/mips/kernel/tynedma.c
@@ -0,0 +1,36 @@
+/*
+ * Tiny Tyne DMA buffer allocator
+ *
+ * Copyright (C) 1995 Ralf Baechle
+ */
+#include <linux/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/bootinfo.h>
+
+#ifdef CONFIG_DESKSTATION_TYNE
+
+static unsigned long allocated;
+
+/*
+ * Not very sophisticated, but should suffice for now...
+ */
+unsigned long deskstation_tyne_dma_alloc(size_t size)
+{
+ unsigned long ret = allocated;
+ allocated += size;
+ if (allocated > boot_info.dma_cache_size)
+ ret = -1;
+ return ret;
+}
+
+void deskstation_tyne_dma_init(void)
+{
+ if (boot_info.machtype != MACH_DESKSTATION_TYNE)
+ return;
+ allocated = 0;
+ printk ("Deskstation Tyne DMA (%luk) buffer initialized.\n",
+ boot_info.dma_cache_size >> 10);
+}
+
+#endif /* CONFIG_DESKSTATION_TYNE */
diff --git a/arch/mips/vm86.c b/arch/mips/kernel/vm86.c
index 454b35fe0..454b35fe0 100644
--- a/arch/mips/vm86.c
+++ b/arch/mips/kernel/vm86.c
diff --git a/arch/mips/ldt.c b/arch/mips/ldt.c
deleted file mode 100644
index 089605cee..000000000
--- a/arch/mips/ldt.c
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * arch/mips/ldt.c
- *
- * Copyright (C) 1994 by Waldorf GMBH,
- * written by Ralf Baechle
- */
-#include <linux/linkage.h>
-#include <linux/errno.h>
-
-asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
-{
- return -ENOSYS;
-}
diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
new file mode 100644
index 000000000..56279fb3e
--- /dev/null
+++ b/arch/mips/lib/Makefile
@@ -0,0 +1,33 @@
+#
+# Makefile for MIPS-specific library files..
+#
+
+.c.s:
+ $(CC) $(CFLAGS) -S $<
+.s.o:
+ $(AS) $(ASFLAGS) -o $*.o $<
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+.S.s:
+ $(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+ $(CC) $(CFLAGS) -c $< -o $*.o
+
+OBJS = dump_tlb.o tinycon.o watch.o
+
+include ../../../.config
+
+lib.a: $(OBJS)
+ $(AR) rcs lib.a $(OBJS)
+ sync
+
+dep:
+ $(CPP) -M *.[cS] > .depend
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
+
diff --git a/arch/mips/lib/dump_tlb.c b/arch/mips/lib/dump_tlb.c
new file mode 100644
index 000000000..f730b9fce
--- /dev/null
+++ b/arch/mips/lib/dump_tlb.c
@@ -0,0 +1,161 @@
+/*
+ * Dump R4x00 TLB for debugging purposes.
+ *
+ * Copyright (C) 1994, 1995 by Waldorf Electronics,
+ * written by Ralf Baechle.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+#include <asm/cachectl.h>
+#include <asm/mipsregs.h>
+
+static void
+dump_tlb(int first, int last)
+{
+ int i;
+ int wired;
+ unsigned int pagemask;
+ unsigned long long entryhi, entrylo0, entrylo1;
+
+ wired = read_32bit_cp0_register(CP0_WIRED);
+ printk("Wired: %d", wired);
+
+ for(i=first;i<last;i++)
+ {
+ write_32bit_cp0_register(CP0_INDEX, i);
+ __asm__ __volatile__(
+ ".set\tmips3\n\t"
+ ".set\tnoreorder\n\t"
+ "nop;nop;nop;nop\n\t"
+ "tlbr\n\t"
+ "nop;nop;nop;nop\n\t"
+ ".set\treorder\n\t"
+ ".set\tmips0\n\t");
+ pagemask = read_32bit_cp0_register(CP0_PAGEMASK);
+ entryhi = read_64bit_cp0_register(CP0_ENTRYHI);
+ entrylo0 = read_64bit_cp0_register(CP0_ENTRYLO0);
+ entrylo1 = read_64bit_cp0_register(CP0_ENTRYLO1);
+
+ if((entrylo0|entrylo1) & 2)
+ {
+ /*
+ * Only print entries in use
+ */
+ printk("\nIndex: %2d %08x", i, pagemask);
+
+ printk(" %08x %08x", (unsigned int)(entryhi >> 32),
+ (unsigned int) entryhi);
+ printk(" %08x %08x", (unsigned int)(entrylo0 >> 32),
+ (unsigned int) entrylo0);
+ printk(" %08x %08x", (unsigned int)(entrylo1 >> 32),
+ (unsigned int) entrylo1);
+ }
+ }
+ printk("\n");
+}
+
+void
+dump_tlb_all(void)
+{
+ dump_tlb(0, boot_info.tlb_entries - 1);
+}
+
+void
+dump_tlb_nonwired(void)
+{
+ dump_tlb(read_32bit_cp0_register(CP0_WIRED), boot_info.tlb_entries - 1);
+}
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+
+#include <asm/mipsconfig.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+void
+dump_list_process(struct task_struct *t, void *address)
+{
+ pgd_t *page_dir, *pgd;
+ pmd_t *pmd;
+ pte_t *pte, page;
+ unsigned int addr;
+
+ addr = (unsigned int) address;
+ printk("Addr == %08x\n", addr);
+
+ printk("tasks->tss.pg_dir == %08x\n",
+ (unsigned int) t->tss.pg_dir);
+
+ page_dir = pgd_offset(t, 0);
+ printk("page_dir == %08x\n", (unsigned int) page_dir);
+
+ pgd = pgd_offset(t, addr);
+ printk("pgd == %08x, ", (unsigned int) pgd);
+
+ pmd = pmd_offset(pgd, addr);
+ printk("pmd == %08x, ", (unsigned int) pmd);
+
+ pte = pte_offset(pmd, addr);
+ printk("pte == %08x, ", (unsigned int) pte);
+
+ page = *pte;
+ printk("page == %08x\n", (unsigned int) pte_val(page));
+
+}
+
+void
+dump_list_current(void *address)
+{
+ unsigned int addr, *pt;
+
+ dump_list_process(current, address);
+
+ addr = (unsigned int) address;
+ pt = (unsigned int *) TLB_ROOT + (addr >> 22);
+ printk("L1: *%08x == ", (unsigned int) pt);
+ printk("%08x, ", *pt);
+
+ pt = (unsigned int *) (TLBMAP + ((addr >> 10) & ~3));
+ printk("L2: *%08x == ", (unsigned int) pt);
+ printk("%08x\n", *pt);
+}
+
+#include <asm/segment.h>
+
+unsigned int
+vtop(void *address)
+{
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte;
+ unsigned int addr, paddr;
+
+ addr = (unsigned int) address;
+ pgd = pgd_offset(current, addr);
+ pmd = pmd_offset(pgd, addr);
+ pte = pte_offset(pmd, addr);
+ paddr = (KSEG1 | (unsigned int) pte_val(*pte)) & PAGE_MASK;
+ paddr |= (addr & ~PAGE_MASK);
+
+ return paddr;
+}
+
+void
+dump16(unsigned long *p)
+{
+ int i;
+
+ for(i=0;i<8;i++)
+ {
+ printk("*%08lx == %08lx, ",
+ (unsigned long)p, (unsigned long)*p++);
+ printk("*%08lx == %08lx\n",
+ (unsigned long)p, (unsigned long)*p++);
+ }
+}
+
diff --git a/arch/mips/lib/tinycon.c b/arch/mips/lib/tinycon.c
new file mode 100644
index 000000000..4410986d8
--- /dev/null
+++ b/arch/mips/lib/tinycon.c
@@ -0,0 +1,133 @@
+/* ----------------------------------------------------------------------
+ * console.c
+ *
+ * Copyright (C) 1994 by Waldorf Electronic,
+ * written by Ralf Baechle and Andreas Busse
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ * ---------------------------------------------------------------------- */
+/*
+ * FIXME: This file is hacked to be hardwired for the Deskstation
+ * Only thought as a debugging console output
+ */
+
+#include <linux/tty.h>
+#include <asm/bootinfo.h>
+
+static unsigned int size_x;
+static unsigned int size_y;
+static unsigned short cursor_x;
+static unsigned short cursor_y;
+static volatile unsigned short *vram_addr;
+static int console_needs_init = 1;
+
+extern struct bootinfo boot_info;
+extern struct screen_info screen_info;
+
+/* ----------------------------------------------------------------------
+ * init_console()
+ * ---------------------------------------------------------------------- */
+
+void init_console(void)
+{
+ size_x = 80;
+ size_y = 50;
+ cursor_x = 0;
+ cursor_y = 0;
+
+ vram_addr = (unsigned short *)0xe10b8000;
+
+ console_needs_init = 0;
+}
+
+void
+set_size_x(unsigned int x)
+{
+ size_x = x;
+}
+
+void
+set_size_y(unsigned int y)
+{
+ size_y = y;
+}
+
+void
+set_vram(unsigned short *vram)
+{
+ vram_addr = vram;
+}
+
+void
+set_cursor(unsigned int x, unsigned int y)
+{
+ cursor_x = x;
+ cursor_y = y;
+}
+
+void
+print_char(unsigned int x, unsigned int y, unsigned char c)
+{
+ volatile unsigned short *caddr;
+
+ caddr = vram_addr + (y * size_x) + x;
+ *caddr = (*caddr & 0xff00) | 0x0f00 | (unsigned short) c;
+}
+
+static void
+scroll(void)
+{
+ volatile unsigned short *caddr;
+ register int i;
+
+ caddr = vram_addr;
+ for(i=0; i<size_x * (size_y-1); i++)
+ *(caddr++) = *(caddr + size_x);
+
+ /* blank last line */
+
+ caddr = vram_addr + (size_x * (size_y-1));
+ for(i=0; i<size_x; i++)
+ *(caddr++) = (*caddr & 0xff00) | (unsigned short) ' ';
+}
+
+void print_string(const unsigned char *str)
+{
+ unsigned char c;
+
+ if (console_needs_init)
+ init_console();
+
+ while((c = *str++))
+ switch(c)
+ {
+ case '\n':
+ cursor_x = 0;
+ cursor_y++;
+ if(cursor_y == size_y)
+ {
+ scroll();
+ cursor_y = size_y - 1;
+ }
+ break;
+
+ default:
+ print_char(cursor_x, cursor_y, c);
+ cursor_x++;
+ if(cursor_x == size_x)
+ {
+ cursor_x = 0;
+ cursor_y++;
+ if(cursor_y == size_y)
+ {
+ scroll();
+ cursor_y = size_y - 1;
+ }
+ }
+ break;
+ }
+}
+
+/* end of file */
diff --git a/arch/mips/lib/watch.S b/arch/mips/lib/watch.S
new file mode 100644
index 000000000..36b54d5c0
--- /dev/null
+++ b/arch/mips/lib/watch.S
@@ -0,0 +1,102 @@
+/*
+ * Kernel debug stuff to use the Watch registers.
+ * Usefull to find stack overflows etc.
+ *
+ * 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 Ralf Baechle
+ */
+#include <asm/asm.h>
+#include <asm/mipsregs.h>
+
+ .set noreorder
+/*
+ * Parameter: a0 - logic address to watch
+ * Currently only KSEG0 addresses are allowed!
+ * a1 - set bit #1 to trap on load references
+ * bit #0 to trap on store references
+ * Results : none
+ */
+ LEAF(watch_set)
+ li t0,0x80000000
+ subu a0,t0
+ ori a0,7
+ xori a0,7
+ or a0,a1
+ mtc0 a0,CP0_WATCHLO
+ jr ra
+ mtc0 zero,CP0_WATCHHI
+ END(watch_set)
+
+/*
+ * The stuff below are just some kernel debugging gadgets. It will
+ * go away.
+ */
+
+/*
+ * Parameter: none
+ * Results : none
+ */
+ LEAF(watch_clear)
+ jr ra
+ mtc0 zero,CP0_WATCHLO
+ END(watch_clear)
+
+/*
+ * Parameter: none
+ * Results : none
+ */
+ LEAF(get_sp)
+ jr ra
+ move v0,sp
+ END(get_sp)
+
+/*
+ * Parameter: none
+ * Results : none
+ */
+ LEAF(get_ra)
+ jr ra
+ move v0,ra
+ END(get_ra)
+
+/*
+ * Parameter: none
+ * Results : none
+ */
+ LEAF(get_status)
+ jr ra
+ mfc0 v0,CP0_STATUS
+ END(get_status)
+
+/*
+ * Parameter: none
+ * Results : none
+ */
+ NESTED(print_sp, 24, sp)
+ .mask 0x80000000,16
+ subu sp,24
+ sw ra,16(sp)
+ move a1,sp
+ PRINT("$sp == %08lx\n")
+ lw ra,16(sp)
+ jr ra
+ addiu sp,24
+ END(print_sp)
+
+/*
+ * Parameter: none
+ * Results : none
+ */
+ NESTED(print_st, 24, sp)
+ .mask 0x80000000,16
+ subu sp,24
+ sw ra,16(sp)
+ mfc0 a1,CP0_STATUS
+ PRINT("cp0_status == %08lx\n")
+ lw ra,16(sp)
+ jr ra
+ addiu sp,24
+ END(print_st)
diff --git a/arch/mips/main.c b/arch/mips/main.c
deleted file mode 100644
index 8cb92d5f2..000000000
--- a/arch/mips/main.c
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * arch/mips/main.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- * MIPSified by Ralf Baechle
- */
-
-#include <stdarg.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/bootinfo.h>
-
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/tty.h>
-#include <linux/head.h>
-#include <linux/unistd.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/fs.h>
-#include <linux/ctype.h>
-#include <linux/delay.h>
-#include <linux/utsname.h>
-#include <linux/ioport.h>
-
-extern unsigned long * prof_buffer;
-extern unsigned long prof_len;
-extern char edata, end;
-extern char *linux_banner;
-
-/*
- * we need this inline - forking from kernel space will result
- * in NO COPY ON WRITE (!!!), until an execve is executed. This
- * is no problem, but for the stack. This is handled by not letting
- * main() use the stack at all after fork(). Thus, no function
- * calls - which means inline code for fork too, as otherwise we
- * would use the stack upon exit from 'fork()'.
- *
- * Actually only pause and fork are needed inline, so that there
- * won't be any messing with the stack from main(), but we define
- * some others too.
- */
-#define __NR__exit __NR_exit
-static inline _syscall0(int,idle)
-static inline _syscall0(int,fork)
-
-extern int console_loglevel;
-
-extern char empty_zero_page[PAGE_SIZE];
-extern void init(void);
-extern void init_IRQ(void);
-extern void init_modules(void);
-extern long console_init(long, long);
-extern long kmalloc_init(long,long);
-extern long blk_dev_init(long,long);
-extern long chr_dev_init(long,long);
-extern void floppy_init(void);
-extern void sock_init(void);
-extern long rd_init(long mem_start, int length);
-unsigned long net_dev_init(unsigned long, unsigned long);
-#if 0
-extern long bios32_init(long, long);
-#endif
-
-extern void hd_setup(char *str, int *ints);
-extern void bmouse_setup(char *str, int *ints);
-extern void eth_setup(char *str, int *ints);
-extern void xd_setup(char *str, int *ints);
-extern void mcd_setup(char *str, int *ints);
-extern void st_setup(char *str, int *ints);
-extern void st0x_setup(char *str, int *ints);
-extern void tmc8xx_setup(char *str, int *ints);
-extern void t128_setup(char *str, int *ints);
-extern void pas16_setup(char *str, int *ints);
-extern void generic_NCR5380_setup(char *str, int *intr);
-extern void aha152x_setup(char *str, int *ints);
-extern void aha1542_setup(char *str, int *ints);
-extern void aha274x_setup(char *str, int *ints);
-extern void scsi_luns_setup(char *str, int *ints);
-extern void sound_setup(char *str, int *ints);
-#ifdef CONFIG_SBPCD
-extern void sbpcd_setup(char *str, int *ints);
-#endif CONFIG_SBPCD
-#ifdef CONFIG_CDU31A
-extern void cdu31a_setup(char *str, int *ints);
-#endif CONFIG_CDU31A
-void ramdisk_setup(char *str, int *ints);
-
-#ifdef CONFIG_SYSVIPC
-extern void ipc_init(void);
-#endif
-#ifdef CONFIG_SCSI
-extern unsigned long scsi_dev_init(unsigned long, unsigned long);
-#endif
-
-/*
- * This is set up by the setup-routine at boot-time
- */
-#define PARAM empty_zero_page
-#define EXT_MEM_K (*(unsigned short *) (PARAM+2))
-#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
-#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
-#define RAMDISK_SIZE (*(unsigned short *) (PARAM+0x1F8))
-#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))
-#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))
-
-/*
- * Defaults, may be overwritten by milo
- */
-#define SCREEN_INFO {0,0,{0,0},52,3,80,4626,3,9,50}
-
-/*
- * Information passed by milo
- */
-struct bootinfo boot_info;
-struct screen_info screen_info = SCREEN_INFO;
-
-/*
- * Boot command-line arguments
- */
-extern void copy_options(char * to, char * from);
-void parse_options(char *line);
-#define MAX_INIT_ARGS 8
-#define MAX_INIT_ENVS 8
-#define COMMAND_LINE ((char *) (PARAM+2048))
-#define COMMAND_LINE_SIZE 256
-
-extern void time_init(void);
-
-static unsigned long memory_start = 0; /* After mem_init, stores the */
- /* amount of free user memory */
-/* static */ unsigned long memory_end = 0;
-/* static unsigned long low_memory_start = 0; */
-
-int rows, cols;
-
-struct drive_info_struct { char dummy[32]; } drive_info;
-
-unsigned char aux_device_present;
-int ramdisk_size;
-int root_mountflags;
-
-static char command_line[COMMAND_LINE_SIZE] = { 0, };
-
-struct {
- char *str;
- void (*setup_func)(char *, int *);
-} bootsetups[] = {
- { "ramdisk=", ramdisk_setup },
-#ifdef CONFIG_INET
- { "ether=", eth_setup },
-#endif
-#ifdef CONFIG_SCSI
- { "max_scsi_luns=", scsi_luns_setup },
-#endif
-#ifdef CONFIG_BLK_DEV_HD
- { "hd=", hd_setup },
-#endif
-#ifdef CONFIG_CHR_DEV_ST
- { "st=", st_setup },
-#endif
-#ifdef CONFIG_BUSMOUSE
- { "bmouse=", bmouse_setup },
-#endif
-#ifdef CONFIG_SCSI_SEAGATE
- { "st0x=", st0x_setup },
- { "tmc8xx=", tmc8xx_setup },
-#endif
-#ifdef CONFIG_SCSI_T128
- { "t128=", t128_setup },
-#endif
-#ifdef CONFIG_SCSI_PAS16
- { "pas16=", pas16_setup },
-#endif
-#ifdef CONFIG_SCSI_GENERIC_NCR5380
- { "ncr5380=", generic_NCR5380_setup },
-#endif
-#ifdef CONFIG_SCSI_AHA152X
- { "aha152x=", aha152x_setup},
-#endif
-#ifdef CONFIG_SCSI_AHA1542
- { "aha1542=", aha1542_setup},
-#endif
-#ifdef CONFIG_SCSI_AHA274X
- { "aha274x=", aha274x_setup},
-#endif
-#ifdef CONFIG_BLK_DEV_XD
- { "xd=", xd_setup },
-#endif
-#ifdef CONFIG_MCD
- { "mcd=", mcd_setup },
-#endif
-#ifdef CONFIG_SOUND
- { "sound=", sound_setup },
-#endif
-#ifdef CONFIG_SBPCD
- { "sbpcd=", sbpcd_setup },
-#endif CONFIG_SBPCD
-#ifdef CONFIG_CDU31A
- { "cdu31a=", cdu31a_setup },
-#endif CONFIG_CDU31A
- { 0, 0 }
-};
-
-void ramdisk_setup(char *str, int *ints)
-{
- if (ints[0] > 0 && ints[1] >= 0)
- ramdisk_size = ints[1];
-}
-
-unsigned long loops_per_sec = 1;
-
-static void calibrate_delay(void)
-{
- int ticks;
-
- printk("Calibrating delay loop.. ");
- while (loops_per_sec <<= 1) {
- /* wait for "start of" clock tick */
- ticks = jiffies;
- while (ticks == jiffies)
- /* nothing */;
- /* Go .. */
- ticks = jiffies;
- __delay(loops_per_sec);
- ticks = jiffies - ticks;
- if (ticks >= HZ) {
- /*
- * No assembler - should be ok
- */
- loops_per_sec = (loops_per_sec * HZ) / ticks;
- printk("ok - %lu.%02lu BogoMips\n",
- loops_per_sec/500000,
- (loops_per_sec/5000) % 100);
- return;
- }
- }
- printk("failed\n");
-}
-
-int parse_machine_options(char *line)
-{
- /*
- * No special MIPS options yet
- */
- return 0;
-}
-
-asmlinkage void start_kernel(void)
-{
- /*
- * Interrupts are still disabled. Do necessary setups, then
- * enable them
- */
- ROOT_DEV = ORIG_ROOT_DEV;
- drive_info = DRIVE_INFO;
- aux_device_present = AUX_DEVICE_INFO;
-#if 0
- memory_end = (1<<20) + (EXT_MEM_K<<10);
-#else
- memory_end = 0x80800000;
-#endif
- memory_end &= PAGE_MASK;
- ramdisk_size = RAMDISK_SIZE;
- copy_options(command_line,COMMAND_LINE);
-
- if (MOUNT_ROOT_RDONLY)
- root_mountflags |= MS_RDONLY;
- memory_start = 0x7fffffff & (unsigned long) &end;
-
- memory_start = paging_init(memory_start,memory_end);
- trap_init();
- init_IRQ();
- sched_init();
- parse_options(command_line);
- init_modules();
-#ifdef CONFIG_PROFILE
- prof_buffer = (unsigned long *) memory_start;
- prof_len = (unsigned long) &end;
- prof_len >>= 2;
- memory_start += prof_len * sizeof(unsigned long);
-#endif
- memory_start = console_init(memory_start,memory_end);
- memory_start = kmalloc_init(memory_start,memory_end);
- memory_start = chr_dev_init(memory_start,memory_end);
- memory_start = blk_dev_init(memory_start,memory_end);
- sti();
- calibrate_delay();
-#ifdef CONFIG_SCSI
- memory_start = scsi_dev_init(memory_start,memory_end);
-#endif
-#ifdef CONFIG_INET
- memory_start = net_dev_init(memory_start,memory_end);
-#endif
-while(1);
- memory_start = inode_init(memory_start,memory_end);
- memory_start = file_table_init(memory_start,memory_end);
- memory_start = name_cache_init(memory_start,memory_end);
- mem_init(memory_start,memory_end);
- buffer_init();
- time_init();
- floppy_init();
- sock_init();
-#ifdef CONFIG_SYSVIPC
- ipc_init();
-#endif
- sti();
-
- /*
- * Get CPU type
- * FIXME: Not implemented yet
- */
-
- printk(linux_banner);
-
- move_to_user_mode();
- if (!fork()) /* we count on this going ok */
- init();
-/*
- * task[0] is meant to be used as an "idle" task: it may not sleep, but
- * it might do some general things like count free pages or it could be
- * used to implement a reasonable LRU algorithm for the paging routines:
- * anything that can be useful, but shouldn't take time from the real
- * processes.
- *
- * Right now task[0] just does a infinite idle loop.
- */
- for(;;)
- idle();
-}
diff --git a/arch/mips/mkdisk b/arch/mips/mkdisk
new file mode 100644
index 000000000..468d34727
--- /dev/null
+++ b/arch/mips/mkdisk
@@ -0,0 +1,5 @@
+#!/bin/sh
+cp vmlinux vmlinux.tmp
+mipsel-linux-strip -g -x vmlinux.tmp
+mwrite -n vmlinux.tmp a:vmlinux
+rm -f vmlinux.tmp
diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile
index 5063d60c2..6ff21fafd 100644
--- a/arch/mips/mm/Makefile
+++ b/arch/mips/mm/Makefile
@@ -1,5 +1,5 @@
#
-# Makefile for the linux memory manager.
+# Makefile for the linux mips-specific parts of the memory manager.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
@@ -14,11 +14,13 @@
.c.s:
$(CC) $(CFLAGS) -S $<
-OBJS = memory.o swap.o mmap.o mprotect.o kmalloc.o vmalloc.o
+OBJS = fault.o init.o
mm.o: $(OBJS)
$(LD) -r -o mm.o $(OBJS)
+modules:
+
dep:
$(CPP) -M *.c > .depend
diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c
new file mode 100644
index 000000000..9256025d9
--- /dev/null
+++ b/arch/mips/mm/fault.c
@@ -0,0 +1,92 @@
+/*
+ * arch/mips/mm/fault.c
+ *
+ * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
+ * Ported to MIPS by Ralf Baechle
+ */
+#include <linux/config.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/head.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/pgtable.h>
+
+extern void die_if_kernel(char *, struct pt_regs *, long);
+
+/*
+ * This routine handles page faults. It determines the address,
+ * and the problem, and then passes it off to one of the appropriate
+ * routines.
+ */
+asmlinkage void
+do_page_fault(struct pt_regs *regs, unsigned long writeaccess)
+{
+ struct vm_area_struct * vma;
+ unsigned long address;
+
+ /* get the address */
+ __asm__(".set\tmips3\n\t"
+ "dmfc0\t%0,$8\n\t"
+ ".set\tmips0"
+ : "=r" (address));
+
+#if 0
+ printk("do_page_fault() #1: %s %08lx (epc == %08lx)\n",
+ writeaccess ? "writeaccess to" : "readaccess from",
+ address, regs->cp0_epc);
+#endif
+ vma = find_vma(current, address);
+ if (!vma)
+ goto bad_area;
+ if (vma->vm_start <= address)
+ goto good_area;
+ if (!(vma->vm_flags & VM_GROWSDOWN))
+ goto bad_area;
+ if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur)
+ goto bad_area;
+ vma->vm_offset -= vma->vm_start - (address & PAGE_MASK);
+ vma->vm_start = (address & PAGE_MASK);
+/*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
+good_area:
+ if (writeaccess) {
+ if (!(vma->vm_flags & VM_WRITE))
+ goto bad_area;
+ } else {
+ if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+ goto bad_area;
+ }
+ handle_mm_fault(vma, address, writeaccess);
+ return;
+
+/*
+ * Something tried to access memory that isn't in our memory map..
+ * Fix it, but check if it's kernel or user first..
+ */
+bad_area:
+ if (user_mode(regs)) {
+ current->tss.cp0_badvaddr = address;
+ current->tss.error_code = writeaccess;
+ send_sig(SIGSEGV, current, 1);
+ return;
+ }
+ /*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
+ printk(KERN_ALERT "Unable to handle kernel paging request at virtual address %08lx",
+ address);
+ die_if_kernel("Oops", regs, writeaccess);
+ do_exit(SIGKILL);
+}
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
new file mode 100644
index 000000000..37912e2d0
--- /dev/null
+++ b/arch/mips/mm/init.c
@@ -0,0 +1,299 @@
+/*
+ * arch/mips/mm/init.c
+ *
+ * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
+ * Ported to MIPS by Ralf Baechle
+ */
+#include <linux/config.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/head.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+
+#include <asm/cachectl.h>
+#include <asm/vector.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/pgtable.h>
+
+extern void deskstation_tyne_dma_init(void);
+extern void scsi_mem_init(unsigned long);
+extern void sound_mem_init(void);
+extern void die_if_kernel(char *,struct pt_regs *,long);
+extern void show_net_buffers(void);
+
+extern char empty_zero_page[PAGE_SIZE];
+
+/*
+ * BAD_PAGE is the page that is used for page faults when linux
+ * is out-of-memory. Older versions of linux just did a
+ * do_exit(), but using this instead means there is less risk
+ * for a process dying in kernel mode, possibly leaving a inode
+ * unused etc..
+ *
+ * BAD_PAGETABLE is the accompanying page-table: it is initialized
+ * to point to BAD_PAGE entries.
+ *
+ * ZERO_PAGE is a special page that is used for zero-initialized
+ * data and COW.
+ */
+pte_t * __bad_pagetable(void)
+{
+ extern char empty_bad_page_table[PAGE_SIZE];
+ unsigned long page;
+ unsigned long dummy1, dummy2;
+
+ page = ((unsigned long)empty_bad_page_table) + (PT_OFFSET - PAGE_OFFSET);
+#ifdef __R4000__
+ /*
+ * Use 64bit code even for Linux/MIPS 32bit on R4000
+ */
+ __asm__ __volatile__(
+ ".set\tnoreorder\n"
+ ".set\tnoat\n\t"
+ ".set\tmips3\n\t"
+ "dsll32\t$1,%2,0\n\t"
+ "dsrl32\t%2,$1,0\n\t"
+ "or\t%2,$1\n"
+ "1:\tsd\t%2,(%0)\n\t"
+ "subu\t%1,1\n\t"
+ "bnez\t%1,1b\n\t"
+ "addiu\t%0,8\n\t"
+ ".set\tmips0\n\t"
+ ".set\tat\n"
+ ".set\treorder"
+ :"=r" (dummy1),
+ "=r" (dummy2)
+ :"r" (pte_val(BAD_PAGE)),
+ "0" (page),
+ "1" (PAGE_SIZE/8));
+#else
+ __asm__ __volatile__(
+ ".set\tnoreorder\n"
+ "1:\tsw\t%2,(%0)\n\t"
+ "subu\t%1,1\n\t"
+ "bnez\t%1,1b\n\t"
+ "addiu\t%0,4\n\t"
+ ".set\treorder"
+ :"=r" (dummy1),
+ "=r" (dummy2)
+ :"r" (pte_val(BAD_PAGE)),
+ "0" (page),
+ "1" (PAGE_SIZE/4));
+#endif
+
+ return (pte_t *)page;
+}
+
+static inline void
+__zeropage(unsigned long page)
+{
+ unsigned long dummy1, dummy2;
+
+#ifdef __R4000__
+ /*
+ * Use 64bit code even for Linux/MIPS 32bit on R4000
+ */
+ __asm__ __volatile__(
+ ".set\tnoreorder\n"
+ ".set\tnoat\n\t"
+ ".set\tmips3\n"
+ "1:\tsd\t$0,(%0)\n\t"
+ "subu\t%1,1\n\t"
+ "bnez\t%1,1b\n\t"
+ "addiu\t%0,8\n\t"
+ ".set\tmips0\n\t"
+ ".set\tat\n"
+ ".set\treorder"
+ :"=r" (dummy1),
+ "=r" (dummy2)
+ :"0" (page),
+ "1" (PAGE_SIZE/8));
+#else
+ __asm__ __volatile__(
+ ".set\tnoreorder\n"
+ "1:\tsw\t$0,(%0)\n\t"
+ "subu\t%1,1\n\t"
+ "bnez\t%1,1b\n\t"
+ "addiu\t%0,4\n\t"
+ ".set\treorder"
+ :"=r" (dummy1),
+ "=r" (dummy2)
+ :"0" (page),
+ "1" (PAGE_SIZE/4));
+#endif
+}
+
+static inline void
+zeropage(unsigned long page)
+{
+ sys_cacheflush((void *)page, PAGE_SIZE, BCACHE);
+ sync_mem();
+ __zeropage(page + (PT_OFFSET - PAGE_OFFSET));
+}
+
+pte_t __bad_page(void)
+{
+ extern char empty_bad_page[PAGE_SIZE];
+ unsigned long page = (unsigned long)empty_bad_page;
+
+ zeropage(page);
+ return pte_mkdirty(mk_pte(page, PAGE_SHARED));
+}
+
+unsigned long __zero_page(void)
+{
+ unsigned long page = (unsigned long) empty_zero_page;
+
+ zeropage(page);
+ return page;
+}
+
+/*
+ * This is horribly inefficient ...
+ */
+void __copy_page(unsigned long from, unsigned long to)
+{
+ /*
+ * Now copy page from uncached KSEG1 to KSEG0. The copy destination
+ * is in KSEG0 so that we keep stupid L2 caches happy.
+ */
+ if(from == (unsigned long) empty_zero_page)
+ {
+ /*
+ * The page copied most is the COW empty_zero_page. Since we
+ * know it's contents we can avoid the writeback reading of
+ * the page. Speeds up the standard case alot.
+ */
+ __zeropage(to);
+ }
+ else
+ {
+ /*
+ * Force writeback of old page to memory. We don't know the
+ * virtual address, so we have to flush the entire cache ...
+ */
+ sys_cacheflush(0, ~0, DCACHE);
+ sync_mem();
+ memcpy((void *) to,
+ (void *) (from + (PT_OFFSET - PAGE_OFFSET)), PAGE_SIZE);
+ }
+ /*
+ * Now writeback the page again if colour has changed.
+ * Actually this does a Hit_Writeback, but due to an artifact in
+ * the R4xx0 implementation this should be slightly faster.
+ * Then sweep chipset controlled secondary caches and the ICACHE.
+ */
+ if (page_colour(from) != page_colour(to))
+ sys_cacheflush(0, ~0, DCACHE);
+ sys_cacheflush(0, ~0, ICACHE);
+}
+
+void show_mem(void)
+{
+ int i,free = 0,total = 0;
+ int shared = 0;
+
+ printk("Mem-info:\n");
+ show_free_areas();
+ printk("Free swap: %6dkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
+ i = (high_memory - PAGE_OFFSET) >> PAGE_SHIFT;
+ while (i-- > 0) {
+ total++;
+ if (!mem_map[i])
+ free++;
+ else
+ shared += mem_map[i]-1;
+ }
+ printk("%d pages of RAM\n", total);
+ printk("%d free pages\n", free);
+ printk("%d pages shared\n", shared);
+ show_buffers();
+#ifdef CONFIG_NET
+ show_net_buffers();
+#endif
+}
+
+extern unsigned long free_area_init(unsigned long, unsigned long);
+
+unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
+{
+ pgd_init((unsigned long)swapper_pg_dir - (PT_OFFSET - PAGE_OFFSET));
+ return free_area_init(start_mem, end_mem);
+}
+
+void mem_init(unsigned long start_mem, unsigned long end_mem)
+{
+ int codepages = 0;
+ int datapages = 0;
+ unsigned long tmp;
+ extern int _etext;
+
+ end_mem &= PAGE_MASK;
+ high_memory = end_mem;
+
+ /* mark usable pages in the mem_map[] */
+ start_mem = PAGE_ALIGN(start_mem);
+
+ tmp = start_mem;
+ while (tmp < high_memory) {
+ mem_map[MAP_NR(tmp)] = 0;
+ tmp += PAGE_SIZE;
+ }
+#ifdef CONFIG_DESKSTATION_TYNE
+ deskstation_tyne_dma_init();
+#endif
+#ifdef CONFIG_SCSI
+ scsi_mem_init(high_memory);
+#endif
+#ifdef CONFIG_SOUND
+ sound_mem_init();
+#endif
+ for (tmp = PAGE_OFFSET ; tmp < high_memory ; tmp += PAGE_SIZE) {
+ if (mem_map[MAP_NR(tmp)]) {
+ if (tmp < (unsigned long) &_etext)
+ codepages++;
+ else if (tmp < start_mem)
+ datapages++;
+ continue;
+ }
+ mem_map[MAP_NR(tmp)] = 1;
+ free_page(tmp);
+ }
+ tmp = nr_free_pages << PAGE_SHIFT;
+ printk("Memory: %luk/%luk available (%dk kernel code, %dk data)\n",
+ tmp >> 10,
+ (high_memory - PAGE_OFFSET) >> 10,
+ codepages << (PAGE_SHIFT-10),
+ datapages << (PAGE_SHIFT-10));
+
+ return;
+}
+
+void si_meminfo(struct sysinfo *val)
+{
+ int i;
+
+ i = high_memory >> PAGE_SHIFT;
+ val->totalram = 0;
+ val->sharedram = 0;
+ val->freeram = nr_free_pages << PAGE_SHIFT;
+ val->bufferram = buffermem;
+ while (i-- > 0) {
+ if (mem_map[i] & MAP_PAGE_RESERVED)
+ continue;
+ val->totalram++;
+ if (!mem_map[i])
+ continue;
+ val->sharedram += mem_map[i]-1;
+ }
+ val->totalram <<= PAGE_SHIFT;
+ val->sharedram <<= PAGE_SHIFT;
+ return;
+}
diff --git a/arch/mips/mm/kmalloc.c b/arch/mips/mm/kmalloc.c
deleted file mode 100644
index 018f8db8f..000000000
--- a/arch/mips/mm/kmalloc.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * linux/mm/kmalloc.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds & Roger Wolff.
- *
- * Written by R.E. Wolff Sept/Oct '93.
- *
- */
-
-/*
- * Modified by Alex Bligh (alex@cconcepts.co.uk) 4 Apr 1994 to use multiple
- * pages. So for 'page' throughout, read 'area'.
- */
-
-#include <linux/mm.h>
-#include <asm/system.h>
-#include <linux/delay.h>
-
-#define GFP_LEVEL_MASK 0xf
-
-/* I want this low enough for a while to catch errors.
- I want this number to be increased in the near future:
- loadable device drivers should use this function to get memory */
-
-#define MAX_KMALLOC_K ((PAGE_SIZE<<(NUM_AREA_ORDERS-1))>>10)
-
-
-/* This defines how many times we should try to allocate a free page before
- giving up. Normally this shouldn't happen at all. */
-#define MAX_GET_FREE_PAGE_TRIES 4
-
-
-/* Private flags. */
-
-#define MF_USED 0xffaa0055
-#define MF_FREE 0x0055ffaa
-
-
-/*
- * Much care has gone into making these routines in this file reentrant.
- *
- * The fancy bookkeeping of nbytesmalloced and the like are only used to
- * report them to the user (oooohhhhh, aaaaahhhhh....) are not
- * protected by cli(). (If that goes wrong. So what?)
- *
- * These routines restore the interrupt status to allow calling with ints
- * off.
- */
-
-/*
- * A block header. This is in front of every malloc-block, whether free or not.
- */
-struct block_header {
- unsigned long bh_flags;
- union {
- unsigned long ubh_length;
- struct block_header *fbh_next;
- } vp;
-};
-
-
-#define bh_length vp.ubh_length
-#define bh_next vp.fbh_next
-#define BH(p) ((struct block_header *)(p))
-
-
-/*
- * The page descriptor is at the front of every page that malloc has in use.
- */
-struct page_descriptor {
- struct page_descriptor *next;
- struct block_header *firstfree;
- int order;
- int nfree;
-};
-
-
-#define PAGE_DESC(p) ((struct page_descriptor *)(((unsigned long)(p)) & PAGE_MASK))
-
-
-/*
- * A size descriptor describes a specific class of malloc sizes.
- * Each class of sizes has its own freelist.
- */
-struct size_descriptor {
- struct page_descriptor *firstfree;
- int size;
- int nblocks;
-
- int nmallocs;
- int nfrees;
- int nbytesmalloced;
- int npages;
- unsigned long gfporder; /* number of pages in the area required */
-};
-
-/*
- * For now it is unsafe to allocate bucket sizes between n & n=16 where n is
- * 4096 * any power of two
- */
-
-struct size_descriptor sizes[] = {
- { NULL, 32,127, 0,0,0,0, 0},
- { NULL, 64, 63, 0,0,0,0, 0 },
- { NULL, 128, 31, 0,0,0,0, 0 },
- { NULL, 252, 16, 0,0,0,0, 0 },
- { NULL, 508, 8, 0,0,0,0, 0 },
- { NULL,1020, 4, 0,0,0,0, 0 },
- { NULL,2040, 2, 0,0,0,0, 0 },
- { NULL,4096-16, 1, 0,0,0,0, 0 },
- { NULL,8192-16, 1, 0,0,0,0, 1 },
- { NULL,16384-16, 1, 0,0,0,0, 2 },
- { NULL,32768-16, 1, 0,0,0,0, 3 },
- { NULL,65536-16, 1, 0,0,0,0, 4 },
- { NULL,131072-16, 1, 0,0,0,0, 5 },
- { NULL, 0, 0, 0,0,0,0, 0 }
-};
-
-
-#define NBLOCKS(order) (sizes[order].nblocks)
-#define BLOCKSIZE(order) (sizes[order].size)
-#define AREASIZE(order) (PAGE_SIZE<<(sizes[order].gfporder))
-
-
-long kmalloc_init (long start_mem,long end_mem)
-{
- int order;
-
-/*
- * Check the static info array. Things will blow up terribly if it's
- * incorrect. This is a late "compile time" check.....
- */
-for (order = 0;BLOCKSIZE(order);order++)
- {
- if ((NBLOCKS (order)*BLOCKSIZE(order) + sizeof (struct page_descriptor)) >
- AREASIZE(order))
- {
- printk ("Cannot use %d bytes out of %d in order = %d block mallocs\n",
- NBLOCKS (order) * BLOCKSIZE(order) +
- sizeof (struct page_descriptor),
- (int) AREASIZE(order),
- BLOCKSIZE (order));
- panic ("This only happens if someone messes with kmalloc");
- }
- }
-return start_mem;
-}
-
-
-
-int get_order (int size)
-{
- int order;
-
- /* Add the size of the header */
- size += sizeof (struct block_header);
- for (order = 0;BLOCKSIZE(order);order++)
- if (size <= BLOCKSIZE (order))
- return order;
- return -1;
-}
-
-void * kmalloc (size_t size, int priority)
-{
- unsigned long flags;
- int order,tries,i,sz;
- struct block_header *p;
- struct page_descriptor *page;
-
-/* Sanity check... */
- if (intr_count && priority != GFP_ATOMIC) {
- static int count = 0;
- if (++count < 5) {
- printk("kmalloc called nonatomically from interrupt %p\n",
- __builtin_return_address(0));
- priority = GFP_ATOMIC;
- }
- }
-
-order = get_order (size);
-if (order < 0)
- {
- printk ("kmalloc of too large a block (%d bytes).\n",size);
- return (NULL);
- }
-
-save_flags(flags);
-
-/* It seems VERY unlikely to me that it would be possible that this
- loop will get executed more than once. */
-tries = MAX_GET_FREE_PAGE_TRIES;
-while (tries --)
- {
- /* Try to allocate a "recently" freed memory block */
- cli ();
- if ((page = sizes[order].firstfree) &&
- (p = page->firstfree))
- {
- if (p->bh_flags == MF_FREE)
- {
- page->firstfree = p->bh_next;
- page->nfree--;
- if (!page->nfree)
- {
- sizes[order].firstfree = page->next;
- page->next = NULL;
- }
- restore_flags(flags);
-
- sizes [order].nmallocs++;
- sizes [order].nbytesmalloced += size;
- p->bh_flags = MF_USED; /* As of now this block is officially in use */
- p->bh_length = size;
- return p+1; /* Pointer arithmetic: increments past header */
- }
- printk ("Problem: block on freelist at %08lx isn't free.\n",(long)p);
- return (NULL);
- }
- restore_flags(flags);
-
-
- /* Now we're in trouble: We need to get a new free page..... */
-
- sz = BLOCKSIZE(order); /* sz is the size of the blocks we're dealing with */
-
- /* This can be done with ints on: This is private to this invocation */
- page = (struct page_descriptor *) __get_free_pages (priority & GFP_LEVEL_MASK, sizes[order].gfporder);
- if (!page) {
- static unsigned long last = 0;
- if (last + 10*HZ < jiffies) {
- last = jiffies;
- printk ("Couldn't get a free page.....\n");
- }
- return NULL;
- }
-#if 0
- printk ("Got page %08x to use for %d byte mallocs....",(long)page,sz);
-#endif
- sizes[order].npages++;
-
- /* Loop for all but last block: */
- for (i=NBLOCKS(order),p=BH (page+1);i > 1;i--,p=p->bh_next)
- {
- p->bh_flags = MF_FREE;
- p->bh_next = BH ( ((long)p)+sz);
- }
- /* Last block: */
- p->bh_flags = MF_FREE;
- p->bh_next = NULL;
-
- page->order = order;
- page->nfree = NBLOCKS(order);
- page->firstfree = BH(page+1);
-#if 0
- printk ("%d blocks per page\n",page->nfree);
-#endif
- /* Now we're going to muck with the "global" freelist for this size:
- this should be uninterruptible */
- cli ();
- /*
- * sizes[order].firstfree used to be NULL, otherwise we wouldn't be
- * here, but you never know....
- */
- page->next = sizes[order].firstfree;
- sizes[order].firstfree = page;
- restore_flags(flags);
- }
-
-/* Pray that printk won't cause this to happen again :-) */
-
-printk ("Hey. This is very funny. I tried %d times to allocate a whole\n"
- "new page for an object only %d bytes long, but some other process\n"
- "beat me to actually allocating it. Also note that this 'error'\n"
- "message is soooo very long to catch your attention. I'd appreciate\n"
- "it if you'd be so kind as to report what conditions caused this to\n"
- "the author of this kmalloc: wolff@dutecai.et.tudelft.nl.\n"
- "(Executive summary: This can't happen)\n",
- MAX_GET_FREE_PAGE_TRIES,
- size);
-return NULL;
-}
-
-
-void kfree_s (void *ptr,int size)
-{
-unsigned long flags;
-int order;
-register struct block_header *p=((struct block_header *)ptr) -1;
-struct page_descriptor *page,*pg2;
-
-page = PAGE_DESC (p);
-order = page->order;
-if ((order < 0) ||
- (order > sizeof (sizes)/sizeof (sizes[0])) ||
- (((long)(page->next)) & ~PAGE_MASK) ||
- (p->bh_flags != MF_USED))
- {
- printk ("kfree of non-kmalloced memory: %p, next= %p, order=%d\n",
- p, page->next, page->order);
- return;
- }
-if (size &&
- size != p->bh_length)
- {
- printk ("Trying to free pointer at %p with wrong size: %d instead of %lu.\n",
- p,size,p->bh_length);
- return;
- }
-size = p->bh_length;
-p->bh_flags = MF_FREE; /* As of now this block is officially free */
-save_flags(flags);
-cli ();
-p->bh_next = page->firstfree;
-page->firstfree = p;
-page->nfree ++;
-
-if (page->nfree == 1)
- { /* Page went from full to one free block: put it on the freelist */
- if (page->next)
- {
- printk ("Page %p already on freelist dazed and confused....\n", page);
- }
- else
- {
- page->next = sizes[order].firstfree;
- sizes[order].firstfree = page;
- }
- }
-
-/* If page is completely free, free it */
-if (page->nfree == NBLOCKS (page->order))
- {
-#if 0
- printk ("Freeing page %08x.\n", (long)page);
-#endif
- if (sizes[order].firstfree == page)
- {
- sizes[order].firstfree = page->next;
- }
- else
- {
- for (pg2=sizes[order].firstfree;
- (pg2 != NULL) && (pg2->next != page);
- pg2=pg2->next)
- /* Nothing */;
- if (pg2 != NULL)
- pg2->next = page->next;
- else
- printk ("Ooops. page %p doesn't show on freelist.\n", page);
- }
-/* FIXME: I'm sure we should do something with npages here (like npages--) */
- free_pages ((long)page, sizes[order].gfporder);
- }
-restore_flags(flags);
-
-/* FIXME: ?? Are these increment & decrement operations guaranteed to be
- * atomic? Could an IRQ not occur between the read & the write?
- * Maybe yes on a x86 with GCC...??
- */
-sizes[order].nfrees++; /* Noncritical (monitoring) admin stuff */
-sizes[order].nbytesmalloced -= size;
-}
diff --git a/arch/mips/mm/memory.c b/arch/mips/mm/memory.c
deleted file mode 100644
index 5872f8bd5..000000000
--- a/arch/mips/mm/memory.c
+++ /dev/null
@@ -1,1295 +0,0 @@
-/*
- * arch/mips/mm/memory.c
- *
- * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
- * Ported to MIPS by Ralf Baechle
- */
-
-/*
- * 05.04.94 - Multi-page memory management added for v1.1.
- * Idea by Alex Bligh (alex@cconcepts.co.uk)
- */
-
-#include <linux/config.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/head.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/ptrace.h>
-#include <linux/mman.h>
-
-#include <asm/system.h>
-#include <asm/segment.h>
-
-unsigned long high_memory = 0;
-
-extern unsigned long pg0[1024]; /* page table for 0-4MB for everybody */
-extern unsigned long invalid_pg_table[1024];
-
-extern void sound_mem_init(void);
-extern void die_if_kernel(char *,struct pt_regs *,long);
-extern void show_net_buffers(void);
-
-/*
- * The free_area_list arrays point to the queue heads of the free areas
- * of different sizes
- */
-int nr_swap_pages = 0;
-int nr_free_pages = 0;
-struct mem_list free_area_list[NR_MEM_LISTS];
-unsigned char * free_area_map[NR_MEM_LISTS];
-
-unsigned short * mem_map = NULL;
-
-/*
- * oom() prints a message (so that the user knows why the process died),
- * and gives the process an untrappable SIGKILL.
- */
-void oom(struct task_struct * task)
-{
- printk("\nOut of memory.\n");
- task->sigaction[SIGKILL-1].sa_handler = NULL;
- task->blocked &= ~(1<<(SIGKILL-1));
- send_sig(SIGKILL,task,1);
-}
-
-static void free_one_table(unsigned long * page_dir)
-{
- int j;
- unsigned long pg_table = *page_dir;
- unsigned long * page_table;
-
- if ((long) pg_table & PAGE_MASK != (long) invalid_pg_table & PAGE_MASK )
- return;
- *page_dir = PAGE_VALID | (unsigned long) invalid_pg_table;
- if (pg_table >= high_memory || !(pg_table & PAGE_VALID)) {
- printk("Bad page table: [%p]=%08lx\n",page_dir,pg_table);
- return;
- }
- if (mem_map[MAP_NR(pg_table)] & MAP_PAGE_RESERVED)
- return;
- page_table = (unsigned long *) (pg_table & PAGE_MASK);
- for (j = 0 ; j < PTRS_PER_PAGE ; j++,page_table++) {
- unsigned long pg = *page_table;
-
- if (!pg)
- continue;
- *page_table = 0;
- if (pg & PAGE_VALID)
- free_page(PAGE_MASK & pg);
- else
- swap_free(pg);
- }
- free_page(PAGE_MASK & pg_table);
-}
-
-/*
- * This function clears all user-level page tables of a process - this
- * is needed by execve(), so that old pages aren't in the way. Note that
- * unlike 'free_page_tables()', this function still leaves a valid
- * page-table-tree in memory: it just removes the user pages. The two
- * functions are similar, but there is a fundamental difference.
- */
-void clear_page_tables(struct task_struct * tsk)
-{
- int i;
- unsigned long pg_dir;
- unsigned long * page_dir;
-
- if (!tsk)
- return;
- if (tsk == task[0])
- panic("task[0] (swapper) doesn't support exec()\n");
- pg_dir = tsk->tss.pg_dir;
- page_dir = (unsigned long *) pg_dir;
- if (!page_dir || page_dir == swapper_pg_dir) {
- printk("Trying to clear kernel page-directory: not good\n");
- return;
- }
- if (mem_map[MAP_NR(pg_dir)] > 1) {
- unsigned long * new_pg;
-
- if (!(new_pg = (unsigned long*) get_free_page(GFP_KERNEL))) {
- oom(tsk);
- return;
- }
- for (i = 768 ; i < 1024 ; i++)
- new_pg[i] = page_dir[i];
- free_page(pg_dir);
- tsk->tss.pg_dir = (unsigned long) new_pg;
- return;
- }
- for (i = 0 ; i < 768 ; i++,page_dir++)
- free_one_table(page_dir);
- invalidate();
- return;
-}
-
-/*
- * This function frees up all page tables of a process when it exits.
- */
-void free_page_tables(struct task_struct * tsk)
-{
- int i;
- unsigned long pg_dir;
- unsigned long * page_dir;
-
- if (!tsk)
- return;
- if (tsk == task[0]) {
- printk("task[0] (swapper) killed: unable to recover\n");
- panic("Trying to free up swapper memory space");
- }
- pg_dir = tsk->tss.pg_dir;
- if (!pg_dir || pg_dir == (unsigned long) swapper_pg_dir) {
- printk("Trying to free kernel page-directory: not good\n");
- return;
- }
- tsk->tss.pg_dir = (unsigned long) swapper_pg_dir;
- if (mem_map[MAP_NR(pg_dir)] > 1) {
- free_page(pg_dir);
- return;
- }
- page_dir = (unsigned long *) pg_dir;
- for (i = 0 ; i < PTRS_PER_PAGE ; i++,page_dir++)
- free_one_table(page_dir);
- free_page(pg_dir);
- invalidate();
-}
-
-/*
- * clone_page_tables() clones the page table for a process - both
- * processes will have the exact same pages in memory. There are
- * probably races in the memory management with cloning, but we'll
- * see..
- */
-int clone_page_tables(struct task_struct * tsk)
-{
- unsigned long pg_dir;
-
- pg_dir = current->tss.pg_dir;
- mem_map[MAP_NR(pg_dir)]++;
- tsk->tss.pg_dir = pg_dir;
- return 0;
-}
-
-/*
- * copy_page_tables() just copies the whole process memory range:
- * note the special handling of RESERVED (ie kernel) pages, which
- * means that they are always shared by all processes.
- */
-int copy_page_tables(struct task_struct * tsk)
-{
- int i;
- unsigned long old_pg_dir, *old_page_dir;
- unsigned long new_pg_dir, *new_page_dir;
-
- if (!(new_pg_dir = get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- old_pg_dir = current->tss.pg_dir;
- tsk->tss.pg_dir = new_pg_dir;
- old_page_dir = (unsigned long *) old_pg_dir;
- new_page_dir = (unsigned long *) new_pg_dir;
- for (i = 0 ; i < PTRS_PER_PAGE ; i++,old_page_dir++,new_page_dir++) {
- int j;
- unsigned long old_pg_table, *old_page_table;
- unsigned long new_pg_table, *new_page_table;
-
- old_pg_table = *old_page_dir;
- if (old_pg_table == (unsigned long) invalid_pg_table)
- continue;
- if (old_pg_table >= high_memory || !(old_pg_table & PAGE_VALID)) {
- printk("copy_page_tables: bad page table: "
- "probable memory corruption\n");
- *old_page_dir = PAGE_TABLE | (unsigned long)invalid_pg_table;
- continue;
- }
- if (mem_map[MAP_NR(old_pg_table)] & MAP_PAGE_RESERVED) {
- *new_page_dir = old_pg_table;
- continue;
- }
- if (!(new_pg_table = get_free_page(GFP_KERNEL))) {
- free_page_tables(tsk);
- return -ENOMEM;
- }
- old_page_table = (unsigned long *) (PAGE_MASK & old_pg_table);
- new_page_table = (unsigned long *) (PAGE_MASK & new_pg_table);
- for (j = 0 ; j < PTRS_PER_PAGE ; j++,old_page_table++,new_page_table++) {
- unsigned long pg;
- pg = *old_page_table;
- if (!pg)
- continue;
- if (!(pg & PAGE_VALID)) {
- *new_page_table = swap_duplicate(pg);
- continue;
- }
- if (pg > high_memory || (mem_map[MAP_NR(pg)] & MAP_PAGE_RESERVED)) {
- *new_page_table = pg;
- continue;
- }
- if (pg & PAGE_COW)
- pg &= ~PAGE_RW;
- if (delete_from_swap_cache(pg))
- pg |= PAGE_DIRTY;
- *new_page_table = pg;
- *old_page_table = pg;
- mem_map[MAP_NR(pg)]++;
- }
- *new_page_dir = new_pg_table | PAGE_TABLE;
- }
- invalidate();
- return 0;
-}
-
-/*
- * a more complete version of free_page_tables which performs with page
- * granularity.
- */
-int unmap_page_range(unsigned long from, unsigned long size)
-{
- unsigned long page, page_dir;
- unsigned long *page_table, *dir;
- unsigned long poff, pcnt, pc;
-
- if (from & ~PAGE_MASK) {
- printk("unmap_page_range called with wrong alignment\n");
- return -EINVAL;
- }
- size = (size + ~PAGE_MASK) >> PAGE_SHIFT;
- dir = PAGE_DIR_OFFSET(current->tss.pg_dir,from);
- poff = (from >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
- if ((pcnt = PTRS_PER_PAGE - poff) > size)
- pcnt = size;
-
- for ( ; size > 0; ++dir, size -= pcnt,
- pcnt = (size > PTRS_PER_PAGE ? PTRS_PER_PAGE : size)) {
- if (!(page_dir = *dir)) {
- poff = 0;
- continue;
- }
- if (!(page_dir & PAGE_VALID)) {
- printk("unmap_page_range: bad page directory.");
- continue;
- }
- page_table = (unsigned long *)(PAGE_MASK & page_dir);
- if (poff) {
- page_table += poff;
- poff = 0;
- }
- for (pc = pcnt; pc--; page_table++) {
- if ((page = *page_table) != (unsigned long) invalid_pg_table) {
- *page_table = (unsigned long) invalid_pg_table;
- if (PAGE_VALID & page) {
- if (!(mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED))
- if (current->mm->rss > 0)
- --current->mm->rss;
- free_page(PAGE_MASK & page);
- } else
- swap_free(page);
- }
- }
- if (pcnt == PTRS_PER_PAGE) {
- *dir = 0;
- free_page(PAGE_MASK & page_dir);
- }
- }
- invalidate();
- return 0;
-}
-
-int zeromap_page_range(unsigned long from, unsigned long size, int mask)
-{
- unsigned long *page_table, *dir;
- unsigned long poff, pcnt;
- unsigned long page;
-
- if (mask) {
- if ((mask & (PAGE_MASK|PAGE_VALID)) != PAGE_VALID) {
- printk("zeromap_page_range: mask = %08x\n",mask);
- return -EINVAL;
- }
- mask |= ZERO_PAGE;
- }
- if (from & ~PAGE_MASK) {
- printk("zeromap_page_range: from = %08lx\n",from);
- return -EINVAL;
- }
- dir = PAGE_DIR_OFFSET(current->tss.pg_dir,from);
- size = (size + ~PAGE_MASK) >> PAGE_SHIFT;
- poff = (from >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
- if ((pcnt = PTRS_PER_PAGE - poff) > size)
- pcnt = size;
-
- while (size > 0) {
- if (PAGE_MASK & *dir == (unsigned long) invalid_pg_table) {
- /* clear page needed here? SRB. */
- if (!(page_table = (unsigned long*) get_free_page(GFP_KERNEL))) {
- invalidate();
- return -ENOMEM;
- }
- if (PAGE_MASK & *dir == (unsigned long) invalid_pg_table) {
- free_page((unsigned long) page_table);
- page_table = (unsigned long *)(PAGE_MASK & *dir++);
- } else
- *dir++ = ((unsigned long) page_table) | PAGE_TABLE;
- } else
- page_table = (unsigned long *)(PAGE_MASK & *dir++);
- page_table += poff;
- poff = 0;
- for (size -= pcnt; pcnt-- ;) {
- if (PAGE_MASK & (page = *page_table) != (unsigned long) invalid_pg_table) {
- *page_table = PAGE_TABLE | (unsigned long) invalid_pg_table;
- if (page & PAGE_VALID) {
- if (!(mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED))
- if (current->mm->rss > 0)
- --current->mm->rss;
- free_page(PAGE_MASK & page);
- } else
- swap_free(page);
- }
- *page_table++ = mask;
- }
- pcnt = (size > PTRS_PER_PAGE ? PTRS_PER_PAGE : size);
- }
- invalidate();
- return 0;
-}
-
-/*
- * Maps a range of physical memory into the requested pages. the old
- * mappings are removed. Any references to nonexistent pages results
- * in null mappings (currently treated as "copy-on-access")
- */
-int remap_page_range(unsigned long from, unsigned long to, unsigned long size, int mask)
-{
- unsigned long *page_table, *dir;
- unsigned long poff, pcnt;
- unsigned long page;
-
- if (mask) {
- if ((mask & (PAGE_MASK|PAGE_VALID)) != PAGE_VALID) {
- printk("remap_page_range: mask = %08x\n",mask);
- return -EINVAL;
- }
- }
- if ((from & ~PAGE_MASK) || (to & ~PAGE_MASK)) {
- printk("remap_page_range: from = %08lx, to=%08lx\n",from,to);
- return -EINVAL;
- }
- dir = PAGE_DIR_OFFSET(current->tss.pg_dir,from);
- size = (size + ~PAGE_MASK) >> PAGE_SHIFT;
- poff = (from >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
- if ((pcnt = PTRS_PER_PAGE - poff) > size)
- pcnt = size;
-
- while (size > 0) {
- if (PAGE_MASK & *dir != (unsigned long) invalid_pg_table) {
- /* clearing page here, needed? SRB. */
- if (!(page_table = (unsigned long*) get_free_page(GFP_KERNEL))) {
- invalidate();
- return -1;
- }
- *dir++ = ((unsigned long) page_table) | PAGE_TABLE;
- }
- else
- page_table = (unsigned long *)(PAGE_MASK & *dir++);
- if (poff) {
- page_table += poff;
- poff = 0;
- }
-
- for (size -= pcnt; pcnt-- ;) {
- if (PAGE_MASK & (page = *page_table) != (unsigned long) invalid_pg_table) {
- *page_table = PAGE_TABLE | (unsigned long) invalid_pg_table;
- if (PAGE_VALID & page) {
- if (!(mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED))
- if (current->mm->rss > 0)
- --current->mm->rss;
- free_page(PAGE_MASK & page);
- } else
- swap_free(page);
- }
-
- /*
- * the first condition should return an invalid access
- * when the page is referenced. current assumptions
- * cause it to be treated as demand allocation in some
- * cases.
- */
- if (!mask)
- *page_table++ = 0; /* not present */
- else if (to >= high_memory)
- *page_table++ = (to | mask);
- else if (!mem_map[MAP_NR(to)])
- *page_table++ = 0; /* not present */
- else {
- *page_table++ = (to | mask);
- if (!(mem_map[MAP_NR(to)] & MAP_PAGE_RESERVED)) {
- ++current->mm->rss;
- mem_map[MAP_NR(to)]++;
- }
- }
- to += PAGE_SIZE;
- }
- pcnt = (size > PTRS_PER_PAGE ? PTRS_PER_PAGE : size);
- }
- invalidate();
- return 0;
-}
-
-/*
- * This function puts a page in memory at the wanted address.
- * It returns the physical address of the page gotten, 0 if
- * out of memory (either when trying to access page-table or
- * page.)
- */
-unsigned long put_page(struct task_struct * tsk,unsigned long page,
- unsigned long address,int prot)
-{
- unsigned long *page_table;
-
- if ((prot & (PAGE_MASK|PAGE_VALID)) != PAGE_VALID)
- printk("put_page: prot = %08x\n",prot);
- if (page >= high_memory) {
- printk("put_page: trying to put page %08lx at %08lx\n",page,address);
- return 0;
- }
- page_table = PAGE_DIR_OFFSET(tsk->tss.pg_dir,address);
- if ((*page_table) & PAGE_VALID)
- page_table = (unsigned long *) (PAGE_MASK & *page_table);
- else {
- printk("put_page: bad page directory entry\n");
- oom(tsk);
- *page_table = BAD_PAGETABLE | PAGE_TABLE;
- return 0;
- }
- page_table += (address >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
- if (*page_table) {
- printk("put_page: page already exists\n");
- *page_table = PAGE_TABLE | (unsigned long) invalid_pg_table;
- invalidate();
- }
- *page_table = page | prot;
-/* no need for invalidate */
- return page;
-}
-
-/*
- * The previous function doesn't work very well if you also want to mark
- * the page dirty: exec.c wants this, as it has earlier changed the page,
- * and we want the dirty-status to be correct (for VM). Thus the same
- * routine, but this time we mark it dirty too.
- */
-unsigned long put_dirty_page(struct task_struct * tsk, unsigned long page, unsigned long address)
-{
- unsigned long tmp, *page_table;
-
- if (page >= high_memory)
- printk("put_dirty_page: trying to put page %08lx at %08lx\n",page,address);
- if (mem_map[MAP_NR(page)] != 1)
- printk("mem_map disagrees with %08lx at %08lx\n",page,address);
- page_table = PAGE_DIR_OFFSET(tsk->tss.pg_dir,address);
- if (PAGE_MASK & *page_table == (unsigned long) invalid_pg_table)
- page_table = (unsigned long *) (PAGE_MASK & *page_table);
- else {
- if (!(tmp = get_free_page(GFP_KERNEL)))
- return 0;
- if (PAGE_MASK & *page_table == (unsigned long) invalid_pg_table) {
- free_page(tmp);
- page_table = (unsigned long *) (PAGE_MASK & *page_table);
- } else {
- *page_table = tmp | PAGE_TABLE;
- page_table = (unsigned long *) tmp;
- }
- }
- page_table += (address >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
- if (*page_table) {
- printk("put_dirty_page: page already exists\n");
- *page_table = PAGE_TABLE | (unsigned long) invalid_pg_table;
- invalidate();
- }
- *page_table = page | (PAGE_DIRTY | PAGE_PRIVATE);
-/* no need for invalidate */
- return page;
-}
-
-/*
- * Note that processing of the dirty bit has already been done
- * before in the assembler part. That way it's not only faster -
- * we also can use the i386 code with very little changes.
- *
- * This routine handles present pages, when users try to write
- * to a shared page. It is done by copying the page to a new address
- * and decrementing the shared-page counter for the old page.
- *
- * Goto-purists beware: the only reason for goto's here is that it results
- * in better assembly code.. The "default" path will see no jumps at all.
- */
-void do_wp_page(struct vm_area_struct * vma, unsigned long address,
- unsigned long error_code)
-{
- unsigned long *pde, pte, old_page, prot;
- unsigned long new_page;
-
- new_page = __get_free_page(GFP_KERNEL);
- pde = PAGE_DIR_OFFSET(vma->vm_task->tss.pg_dir,address);
- pte = *pde;
- if (!(pte & PAGE_VALID))
- goto end_wp_page;
- if ((pte & PAGE_TABLE) != PAGE_TABLE || pte >= high_memory)
- goto bad_wp_pagetable;
- pte &= PAGE_MASK;
- pte += PAGE_PTR(address);
- old_page = *(unsigned long *) pte;
- if (!(old_page & PAGE_VALID))
- goto end_wp_page;
- if (old_page >= high_memory)
- goto bad_wp_page;
- if (old_page & PAGE_RW)
- goto end_wp_page;
- vma->vm_task->mm->min_flt++;
- prot = (old_page & ~PAGE_MASK) | PAGE_RW | PAGE_DIRTY;
- old_page &= PAGE_MASK;
- if (mem_map[MAP_NR(old_page)] != 1) {
- if (new_page) {
- if (mem_map[MAP_NR(old_page)] & MAP_PAGE_RESERVED)
- ++vma->vm_task->mm->rss;
- copy_page(old_page,new_page);
- *(unsigned long *) pte = new_page | prot;
- free_page(old_page);
- invalidate();
- return;
- }
- free_page(old_page);
- oom(vma->vm_task);
- *(unsigned long *) pte = BAD_PAGE | prot;
- invalidate();
- return;
- }
- *(unsigned long *) pte |= PAGE_RW | PAGE_DIRTY;
- invalidate();
- if (new_page)
- free_page(new_page);
- return;
-bad_wp_page:
- printk("do_wp_page: bogus page at address %08lx (%08lx)\n",address,old_page);
- *(unsigned long *) pte = BAD_PAGE | PAGE_SHARED;
- send_sig(SIGKILL, vma->vm_task, 1);
- goto end_wp_page;
-bad_wp_pagetable:
- printk("do_wp_page: bogus page-table at address %08lx (%08lx)\n",address,pte);
- *pde = BAD_PAGETABLE | PAGE_TABLE;
- send_sig(SIGKILL, vma->vm_task, 1);
-end_wp_page:
- if (new_page)
- free_page(new_page);
- return;
-}
-
-/*
- * Ugly, ugly, but the goto's result in better assembly..
- */
-int verify_area(int type, const void * addr, unsigned long size)
-{
- struct vm_area_struct * vma;
- unsigned long start = (unsigned long) addr;
-
- /* If the current user space is mapped to kernel space (for the
- * case where we use a fake user buffer with get_fs/set_fs()) we
- * don't expect to find the address in the user vm map.
- */
- if (get_fs() == get_ds())
- return 0;
-
- for (vma = current->mm->mmap ; ; vma = vma->vm_next) {
- if (!vma)
- goto bad_area;
- if (vma->vm_end > start)
- break;
- }
- if (vma->vm_start <= start)
- goto good_area;
- if (!(vma->vm_flags & VM_GROWSDOWN))
- goto bad_area;
- if (vma->vm_end - start > current->rlim[RLIMIT_STACK].rlim_cur)
- goto bad_area;
-
-good_area:
- if (!wp_works_ok && type == VERIFY_WRITE)
- goto check_wp_fault_by_hand;
- for (;;) {
- struct vm_area_struct * next;
- if (!(vma->vm_page_prot & PAGE_USER))
- goto bad_area;
- if (type != VERIFY_READ && !(vma->vm_page_prot & (PAGE_COW | PAGE_RW)))
- goto bad_area;
- if (vma->vm_end - start >= size)
- return 0;
- next = vma->vm_next;
- if (!next || vma->vm_end != next->vm_start)
- goto bad_area;
- vma = next;
- }
-
-check_wp_fault_by_hand:
- size--;
- size += start & ~PAGE_MASK;
- size >>= PAGE_SHIFT;
- start &= PAGE_MASK;
-
- for (;;) {
- if (!(vma->vm_page_prot & (PAGE_COW | PAGE_RW)))
- goto bad_area;
- do_wp_page(vma, start, PAGE_VALID);
- if (!size)
- return 0;
- size--;
- start += PAGE_SIZE;
- if (start < vma->vm_end)
- continue;
- vma = vma->vm_next;
- if (!vma || vma->vm_start != start)
- break;
- }
-
-bad_area:
- return -EFAULT;
-}
-
-static inline void get_empty_page(struct task_struct * tsk, unsigned long address)
-{
- unsigned long tmp;
-
- if (!(tmp = get_free_page(GFP_KERNEL))) {
- oom(tsk);
- tmp = BAD_PAGE;
- }
- if (!put_page(tsk,tmp,address,PAGE_PRIVATE))
- free_page(tmp);
-}
-
-/*
- * try_to_share() checks the page at address "address" in the task "p",
- * to see if it exists, and if it is clean. If so, share it with the current
- * task.
- *
- * NOTE! This assumes we have checked that p != current, and that they
- * share the same inode and can generally otherwise be shared.
- */
-static int try_to_share(unsigned long to_address, struct vm_area_struct * to_area,
- unsigned long from_address, struct vm_area_struct * from_area,
- unsigned long newpage)
-{
- unsigned long from;
- unsigned long to;
- unsigned long from_page;
- unsigned long to_page;
-
- from_page = (unsigned long)PAGE_DIR_OFFSET(from_area->vm_task->tss.pg_dir,from_address);
- to_page = (unsigned long)PAGE_DIR_OFFSET(to_area->vm_task->tss.pg_dir,to_address);
-/* is there a page-directory at from? */
- from = *(unsigned long *) from_page;
- if (from & PAGE_MASK == (unsigned long) invalid_pg_table)
- return 0;
- from &= PAGE_MASK;
- from_page = from + PAGE_PTR(from_address);
- from = *(unsigned long *) from_page;
-/* is the page present? */
- if (!(from & PAGE_VALID))
- return 0;
-/* if it is private, it must be clean to be shared */
- if (from & PAGE_DIRTY) {
- if (from_area->vm_page_prot & PAGE_COW)
- return 0;
- if (!(from_area->vm_page_prot & PAGE_RW))
- return 0;
- }
-/* is the page reasonable at all? */
- if (from >= high_memory)
- return 0;
- if (mem_map[MAP_NR(from)] & MAP_PAGE_RESERVED)
- return 0;
-/* is the destination ok? */
- to = *(unsigned long *) to_page;
- if (to & PAGE_MASK == (unsigned long) invalid_pg_table)
- return 0;
- to &= PAGE_MASK;
- to_page = to + PAGE_PTR(to_address);
- if (*(unsigned long *) to_page)
- return 0;
-/* do we copy? */
- if (newpage) {
- if (in_swap_cache(from)) { /* implies PAGE_DIRTY */
- if (from_area->vm_page_prot & PAGE_COW)
- return 0;
- if (!(from_area->vm_page_prot & PAGE_RW))
- return 0;
- }
- copy_page((from & PAGE_MASK), newpage);
- *(unsigned long *) to_page = newpage | to_area->vm_page_prot;
- return 1;
- }
-/* do a final swap-cache test before sharing them.. */
- if (in_swap_cache(from)) {
- if (from_area->vm_page_prot & PAGE_COW)
- return 0;
- if (!(from_area->vm_page_prot & PAGE_RW))
- return 0;
- from |= PAGE_DIRTY;
- *(unsigned long *) from_page = from;
- delete_from_swap_cache(from);
- invalidate();
- }
- mem_map[MAP_NR(from)]++;
-/* fill in the 'to' field, checking for COW-stuff */
- to = (from & (PAGE_MASK | PAGE_DIRTY)) | to_area->vm_page_prot;
- if (to & PAGE_COW)
- to &= ~PAGE_RW;
- *(unsigned long *) to_page = to;
-/* Check if we need to do anything at all to the 'from' field */
- if (!(from & PAGE_RW))
- return 1;
- if (!(from_area->vm_page_prot & PAGE_COW))
- return 1;
-/* ok, need to mark it read-only, so invalidate any possible old TB entry */
- from &= ~PAGE_RW;
- *(unsigned long *) from_page = from;
- invalidate();
- return 1;
-}
-
-/*
- * share_page() tries to find a process that could share a page with
- * the current one.
- *
- * We first check if it is at all feasible by checking inode->i_count.
- * It should be >1 if there are other tasks sharing this inode.
- */
-static int share_page(struct vm_area_struct * area, unsigned long address,
- unsigned long error_code, unsigned long newpage)
-{
- struct inode * inode;
- struct task_struct ** p;
- unsigned long offset;
- unsigned long from_address;
- unsigned long give_page;
-
- if (!area || !(inode = area->vm_inode) || inode->i_count < 2)
- return 0;
- /* do we need to copy or can we just share? */
- give_page = 0;
- if ((area->vm_page_prot & PAGE_COW) && (error_code & PAGE_RW)) {
- if (!newpage)
- return 0;
- give_page = newpage;
- }
- offset = address - area->vm_start + area->vm_offset;
- for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
- struct vm_area_struct * mpnt;
- if (!*p)
- continue;
- if (area->vm_task == *p)
- continue;
- /* Now see if there is something in the VMM that
- we can share pages with */
- for (mpnt = (*p)->mm->mmap; mpnt; mpnt = mpnt->vm_next) {
- /* must be same inode */
- if (mpnt->vm_inode != inode)
- continue;
- /* offsets must be mutually page-aligned */
- if ((mpnt->vm_offset ^ area->vm_offset) & ~PAGE_MASK)
- continue;
- /* the other area must actually cover the wanted page.. */
- from_address = offset + mpnt->vm_start - mpnt->vm_offset;
- if (from_address < mpnt->vm_start || from_address >= mpnt->vm_end)
- continue;
- /* .. NOW we can actually try to use the same physical page */
- if (!try_to_share(address, area, from_address, mpnt, give_page))
- continue;
- /* free newpage if we never used it.. */
- if (give_page || !newpage)
- return 1;
- free_page(newpage);
- return 1;
- }
- }
- return 0;
-}
-
-/*
- * fill in an empty page-table if none exists.
- */
-static inline unsigned long get_empty_pgtable(struct task_struct * tsk,unsigned long address)
-{
- unsigned long page;
- unsigned long *p;
-
- p = PAGE_DIR_OFFSET(tsk->tss.pg_dir,address);
- if (*p & PAGE_MASK == (unsigned long) invalid_pg_table)
- return *p;
- if (*p) {
- printk("get_empty_pgtable: bad page-directory entry \n");
- *p = 0;
- }
- page = get_free_page(GFP_KERNEL);
- p = PAGE_DIR_OFFSET(tsk->tss.pg_dir,address);
- if (*p & PAGE_MASK == (unsigned long) invalid_pg_table) {
- free_page(page);
- return *p;
- }
- if (*p) {
- printk("get_empty_pgtable: bad page-directory entry \n");
- *p = 0;
- }
- if (page) {
- *p = page | PAGE_TABLE;
- return *p;
- }
- oom(current);
- *p = BAD_PAGETABLE | PAGE_TABLE;
- return 0;
-}
-
-static inline void do_swap_page(struct vm_area_struct * vma,
- unsigned long address, unsigned long * pge, unsigned long entry)
-{
- unsigned long page;
-
- if (vma->vm_ops && vma->vm_ops->swapin)
- page = vma->vm_ops->swapin(vma, entry);
- else
- page = swap_in(entry);
- if (*pge != entry) {
- free_page(page);
- return;
- }
- page = page | vma->vm_page_prot;
- if (mem_map[MAP_NR(page)] > 1 && (page & PAGE_COW))
- page &= ~PAGE_RW;
- ++vma->vm_task->mm->rss;
- ++vma->vm_task->mm->maj_flt;
- *pge = page;
- return;
-}
-
-void do_no_page(struct vm_area_struct * vma, unsigned long address,
- unsigned long error_code)
-{
- unsigned long page, entry, prot;
-
- page = get_empty_pgtable(vma->vm_task,address);
- if (!page)
- return;
- page &= PAGE_MASK;
- page += PAGE_PTR(address);
- entry = *(unsigned long *) page;
- if (entry & PAGE_VALID)
- return;
- if (entry) {
- do_swap_page(vma, address, (unsigned long *) page, entry);
- return;
- }
- address &= PAGE_MASK;
-
- if (!vma->vm_ops || !vma->vm_ops->nopage) {
- ++vma->vm_task->mm->rss;
- ++vma->vm_task->mm->min_flt;
- get_empty_page(vma->vm_task,address);
- return;
- }
- page = get_free_page(GFP_KERNEL);
- if (share_page(vma, address, error_code, page)) {
- ++vma->vm_task->mm->min_flt;
- ++vma->vm_task->mm->rss;
- return;
- }
- if (!page) {
- oom(current);
- put_page(vma->vm_task, BAD_PAGE, address, PAGE_PRIVATE);
- return;
- }
- ++vma->vm_task->mm->maj_flt;
- ++vma->vm_task->mm->rss;
- prot = vma->vm_page_prot;
- /*
- * The fourth argument is "no_share", which tells the low-level code
- * to copy, not share the page even if sharing is possible. It's
- * essentially an early COW detection ("moo at 5 AM").
- */
- page = vma->vm_ops->nopage(vma, address, page, (error_code & PAGE_RW) && (prot & PAGE_COW));
- if (share_page(vma, address, error_code, 0)) {
- free_page(page);
- return;
- }
- /*
- * This silly early PAGE_DIRTY setting removes a race
- * due to the bad i386 page protection.
- */
- if (error_code & PAGE_RW) {
- prot |= PAGE_DIRTY; /* can't be COW-shared: see "no_share" above */
- } else if ((prot & PAGE_COW) && mem_map[MAP_NR(page)] > 1)
- prot &= ~PAGE_RW;
- if (put_page(vma->vm_task, page, address, prot))
- return;
- free_page(page);
- oom(current);
-}
-
-/*
- * This routine handles page faults. It determines the address,
- * and the problem, and then passes it off to one of the appropriate
- * routines.
- */
-asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
-{
- struct vm_area_struct * vma;
- unsigned long address;
- unsigned long page;
-
- /* get the address */
- __asm__("dmfc0\t%0,$8":"=r" (address));
- for (vma = current->mm->mmap ; ; vma = vma->vm_next) {
- if (!vma)
- goto bad_area;
- if (vma->vm_end > address)
- break;
- }
- if (vma->vm_start <= address)
- goto good_area;
- if (!(vma->vm_flags & VM_GROWSDOWN))
- goto bad_area;
- if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur)
- goto bad_area;
- vma->vm_offset -= vma->vm_start - (address & PAGE_MASK);
- vma->vm_start = (address & PAGE_MASK);
-/*
- * Ok, we have a good vm_area for this memory access, so
- * we can handle it..
- */
-good_area:
-#if 0
- if (regs->eflags & VM_MASK) {
- unsigned long bit = (address - 0xA0000) >> PAGE_SHIFT;
- if (bit < 32)
- current->screen_bitmap |= 1 << bit;
- }
-#endif
- if (!(vma->vm_page_prot & PAGE_USER))
- goto bad_area;
- if (error_code & PAGE_VALID) {
- if (!(vma->vm_page_prot & (PAGE_RW | PAGE_COW)))
- goto bad_area;
- do_wp_page(vma, address, error_code);
- return;
- }
- do_no_page(vma, address, error_code);
- return;
-
-/*
- * Something tried to access memory that isn't in our memory map..
- * Fix it, but check if it's kernel or user first..
- */
-bad_area:
- if (error_code & PAGE_USER) {
- current->tss.cp0_badvaddr = address;
- current->tss.error_code = error_code;
- current->tss.trap_no = 14;
- send_sig(SIGSEGV, current, 1);
- return;
- }
-/*
- * Oops. The kernel tried to access some bad page. We'll have to
- * terminate things with extreme prejudice.
- */
- if (wp_works_ok < 0 && address == TASK_SIZE && (error_code & PAGE_VALID)) {
- wp_works_ok = 1;
- pg0[0] = PAGE_SHARED;
- printk("This processor honours the WP bit even when in supervisor mode. Good.\n");
- return;
- }
- if ((unsigned long) (address-TASK_SIZE) < PAGE_SIZE) {
- printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
- pg0[0] = PAGE_SHARED;
- } else
- printk(KERN_ALERT "Unable to handle kernel paging request");
- printk(" at virtual address %08lx\n",address);
- printk(KERN_ALERT "current->tss.pg_dir = %08lx\n", current->tss.pg_dir);
- page = ((unsigned long *) page)[address >> 22];
- printk(KERN_ALERT "*pde = %08lx\n", page);
- if (page & PAGE_VALID) {
- page &= PAGE_MASK;
- address &= 0x003ff000;
- page = ((unsigned long *) page)[address >> PAGE_SHIFT];
- printk(KERN_ALERT "*pte = %08lx\n", page);
- }
- die_if_kernel("Oops", regs, error_code);
- do_exit(SIGKILL);
-}
-
-/*
- * BAD_PAGE is the page that is used for page faults when linux
- * is out-of-memory. Older versions of linux just did a
- * do_exit(), but using this instead means there is less risk
- * for a process dying in kernel mode, possibly leaving a inode
- * unused etc..
- *
- * BAD_PAGETABLE is the accompanying page-table: it is initialized
- * to point to BAD_PAGE entries.
- *
- * ZERO_PAGE is a special page that is used for zero-initialized
- * data and COW.
- */
-unsigned long __bad_pagetable(void)
-{
- extern char empty_bad_page_table[PAGE_SIZE];
- unsigned long dummy;
-
- __asm__ __volatile__(
- ".set\tnoreorder\n\t"
- "1:\tsw\t%2,(%0)\n\t"
- "subu\t%1,%1,1\n\t"
- "bne\t$0,%1,1b\n\t"
- "addiu\t%0,%0,1\n\t"
- ".set\treorder"
- :"=r" (dummy),
- "=r" (dummy)
- :"r" (BAD_PAGE + PAGE_TABLE),
- "0" ((long) empty_bad_page_table),
- "1" (PTRS_PER_PAGE));
-
- return (unsigned long) empty_bad_page_table;
-}
-
-unsigned long __bad_page(void)
-{
- extern char empty_bad_page[PAGE_SIZE];
- unsigned long dummy;
-
- __asm__ __volatile__(
- ".set\tnoreorder\n\t"
- "1:\tsw\t$0,(%0)\n\t"
- "subu\t%1,%1,1\n\t"
- "bne\t$0,%1,1b\n\t"
- "addiu\t%0,%0,1\n\t"
- ".set\treorder"
- :"=r" (dummy),
- "=r" (dummy)
- :"0" ((long) empty_bad_page),
- "1" (PTRS_PER_PAGE));
-
- return (unsigned long) empty_bad_page;
-}
-
-unsigned long __zero_page(void)
-{
- extern char empty_zero_page[PAGE_SIZE];
- unsigned long dummy;
-
- __asm__ __volatile__(
- ".set\tnoreorder\n\t"
- "1:\tsw\t$0,(%0)\n\t"
- "subu\t%1,%1,1\n\t"
- "bne\t$0,%1,1b\n\t"
- "addiu\t%0,%0,1\n\t"
- ".set\treorder"
- :"=r" (dummy),
- "=r" (dummy)
- :"0" ((long) empty_zero_page),
- "1" (PTRS_PER_PAGE));
-
- return (unsigned long) empty_zero_page;
-}
-
-void show_mem(void)
-{
- int i,free = 0,total = 0,reserved = 0;
- int shared = 0;
-
- printk("Mem-info:\n");
- show_free_areas();
- printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
- i = high_memory >> PAGE_SHIFT;
- while (i-- > 0) {
- total++;
- if (mem_map[i] & MAP_PAGE_RESERVED)
- reserved++;
- else if (!mem_map[i])
- free++;
- else
- shared += mem_map[i]-1;
- }
- printk("%d pages of RAM\n",total);
- printk("%d free pages\n",free);
- printk("%d reserved pages\n",reserved);
- printk("%d pages shared\n",shared);
- show_buffers();
-#ifdef CONFIG_NET
- show_net_buffers();
-#endif
-}
-
-#if 0
-extern unsigned long free_area_init(unsigned long, unsigned long);
-
-/*
- * paging_init() sets up the page tables - note that the first 4MB are
- * already mapped by head.S.
- *
- * This routines also unmaps the page at virtual kernel address 0, so
- * that we can trap those pesky NULL-reference errors in the kernel.
- */
-unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
-{
- unsigned long * pg_dir;
- unsigned long * pg_table;
- unsigned long tmp;
- unsigned long address;
-
- start_mem = PAGE_ALIGN(start_mem);
- address = 0;
- pg_dir = swapper_pg_dir;
- while (address < end_mem) {
- /*
- * at virtual addr 0xC0000000
- */
- tmp = *(pg_dir + 768);
- tmp &= PAGE_MASK;
- if (!tmp) {
- tmp = start_mem | PAGE_TABLE;
- *(pg_dir + 768) = tmp;
- start_mem += PAGE_SIZE;
- }
- /*
- * also map it in at 0x0000000 for init
- */
- *pg_dir = tmp;
- pg_dir++;
- pg_table = (unsigned long *) (tmp & PAGE_MASK);
- for (tmp = 0 ; tmp < PTRS_PER_PAGE ; tmp++,pg_table++) {
- if (address < end_mem)
- *pg_table = address | PAGE_SHARED;
- else
- *pg_table = 0;
- address += PAGE_SIZE;
- }
- }
- invalidate();
- return free_area_init(start_mem, end_mem);
-}
-#endif
-
-void mem_init(unsigned long start_mem, unsigned long end_mem)
-{
- int codepages = 0;
- int reservedpages = 0;
- int datapages = 0;
- unsigned long tmp;
- extern int etext;
-
- cli();
- end_mem &= PAGE_MASK;
- high_memory = end_mem;
-
- /* mark usable pages in the mem_map[] */
- start_mem = PAGE_ALIGN(start_mem);
-
- while (start_mem < high_memory) {
- mem_map[MAP_NR(start_mem)] = 0;
- start_mem += PAGE_SIZE;
- }
-#ifdef CONFIG_SOUND
- sound_mem_init();
-#endif
- for (tmp = 0 ; tmp < high_memory ; tmp += PAGE_SIZE) {
- if (mem_map[MAP_NR(tmp)]) {
- /*
- * Don't have any reserved pages
- */
- if (0)
- reservedpages++;
- else if (tmp < (0x7fffffff & (unsigned long) &etext))
- codepages++;
- else
- datapages++;
- continue;
- }
- mem_map[MAP_NR(tmp)] = 1;
- free_page(tmp);
- }
- tmp = nr_free_pages << PAGE_SHIFT;
- printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data)\n",
- tmp >> 10,
- high_memory >> 10,
- codepages << (PAGE_SHIFT-10),
- reservedpages << (PAGE_SHIFT-10),
- datapages << (PAGE_SHIFT-10));
-
-#if 0
- /*
- * No need to cope with Intel bugs
- */
- wp_works_ok = 1;
-#endif
- invalidate();
- return;
-}
-
-void si_meminfo(struct sysinfo *val)
-{
- int i;
-
- i = high_memory >> PAGE_SHIFT;
- val->totalram = 0;
- val->sharedram = 0;
- val->freeram = nr_free_pages << PAGE_SHIFT;
- val->bufferram = buffermem;
- while (i-- > 0) {
- if (mem_map[i] & MAP_PAGE_RESERVED)
- continue;
- val->totalram++;
- if (!mem_map[i])
- continue;
- val->sharedram += mem_map[i]-1;
- }
- val->totalram <<= PAGE_SHIFT;
- val->sharedram <<= PAGE_SHIFT;
- return;
-}
-
-
-/*
- * This handles a generic mmap of a disk file.
- */
-static unsigned long file_mmap_nopage(struct vm_area_struct * area, unsigned long address,
- unsigned long page, int no_share)
-{
- struct inode * inode = area->vm_inode;
- unsigned int block;
- int nr[8];
- int i, *p;
-
- address &= PAGE_MASK;
- block = address - area->vm_start + area->vm_offset;
- block >>= inode->i_sb->s_blocksize_bits;
- i = PAGE_SIZE >> inode->i_sb->s_blocksize_bits;
- p = nr;
- do {
- *p = bmap(inode,block);
- i--;
- block++;
- p++;
- } while (i > 0);
- return bread_page(page, inode->i_dev, nr, inode->i_sb->s_blocksize, no_share);
-}
-
-struct vm_operations_struct file_mmap = {
- NULL, /* open */
- NULL, /* close */
- file_mmap_nopage, /* nopage */
- NULL, /* wppage */
- NULL, /* share */
- NULL, /* unmap */
-};
diff --git a/arch/mips/mm/mmap.c b/arch/mips/mm/mmap.c
deleted file mode 100644
index dbe63b55e..000000000
--- a/arch/mips/mm/mmap.c
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
- * linux/mm/mmap.c
- *
- * Written by obz.
- */
-#include <linux/stat.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/shm.h>
-#include <linux/errno.h>
-#include <linux/mman.h>
-#include <linux/string.h>
-#include <linux/malloc.h>
-
-#include <asm/segment.h>
-#include <asm/system.h>
-
-static int anon_map(struct inode *, struct file *, struct vm_area_struct *);
-
-/*
- * description of effects of mapping type and prot in current implementation.
- * this is due to the limited x86 page protection hardware. The expected
- * behavior is in parens:
- *
- * map_type prot
- * PROT_NONE PROT_READ PROT_WRITE PROT_EXEC
- * MAP_SHARED r: (no) no r: (yes) yes r: (no) yes r: (no) yes
- * w: (no) no w: (no) no w: (yes) yes w: (no) no
- * x: (no) no x: (no) yes x: (no) yes x: (yes) yes
- *
- * MAP_PRIVATE r: (no) no r: (yes) yes r: (no) yes r: (no) yes
- * w: (no) no w: (no) no w: (copy) copy w: (no) no
- * x: (no) no x: (no) yes x: (no) yes x: (yes) yes
- *
- */
-
-int do_mmap(struct file * file, unsigned long addr, unsigned long len,
- unsigned long prot, unsigned long flags, unsigned long off)
-{
- int mask, error;
- struct vm_area_struct * vma;
-
- if ((len = PAGE_ALIGN(len)) == 0)
- return addr;
-
- if (addr > TASK_SIZE || len > TASK_SIZE || addr > TASK_SIZE-len)
- return -EINVAL;
-
- /* offset overflow? */
- if (off + len < off)
- return -EINVAL;
-
- /*
- * do simple checking here so the lower-level routines won't have
- * to. we assume access permissions have been handled by the open
- * of the memory object, so we don't do any here.
- */
-
- if (file != NULL) {
- switch (flags & MAP_TYPE) {
- case MAP_SHARED:
- if ((prot & PROT_WRITE) && !(file->f_mode & 2))
- return -EACCES;
- /* fall through */
- case MAP_PRIVATE:
- if (!(file->f_mode & 1))
- return -EACCES;
- break;
-
- default:
- return -EINVAL;
- }
- if ((flags & MAP_DENYWRITE) && (file->f_inode->i_wcount > 0))
- return -ETXTBSY;
- } else if ((flags & MAP_TYPE) == MAP_SHARED)
- return -EINVAL;
-
- /*
- * obtain the address to map to. we verify (or select) it and ensure
- * that it represents a valid section of the address space.
- */
-
- if (flags & MAP_FIXED) {
- if (addr & ~PAGE_MASK)
- return -EINVAL;
- if (len > TASK_SIZE || addr > TASK_SIZE - len)
- return -EINVAL;
- } else {
- addr = get_unmapped_area(len);
- if (!addr)
- return -ENOMEM;
- }
-
- /*
- * determine the object being mapped and call the appropriate
- * specific mapper. the address has already been validated, but
- * not unmapped, but the maps are removed from the list.
- */
- if (file && (!file->f_op || !file->f_op->mmap))
- return -ENODEV;
- mask = PAGE_VALID;
- if (prot & (PROT_READ | PROT_EXEC))
- mask |= PAGE_READONLY;
- if (prot & PROT_WRITE)
- if ((flags & MAP_TYPE) == MAP_PRIVATE)
- mask |= PAGE_COPY;
- else
- mask |= PAGE_SHARED;
-
- vma = (struct vm_area_struct *)kmalloc(sizeof(struct vm_area_struct),
- GFP_KERNEL);
- if (!vma)
- return -ENOMEM;
-
- vma->vm_task = current;
- vma->vm_start = addr;
- vma->vm_end = addr + len;
- vma->vm_page_prot = mask;
- vma->vm_flags = prot & (VM_READ | VM_WRITE | VM_EXEC);
- vma->vm_flags |= flags & (VM_GROWSDOWN | VM_DENYWRITE | VM_EXECUTABLE);
-
- if (file) {
- if (file->f_mode & 1)
- vma->vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
- if (flags & MAP_SHARED) {
- vma->vm_flags |= VM_SHARED | VM_MAYSHARE;
- if (!(file->f_mode & 2))
- vma->vm_flags &= ~VM_MAYWRITE;
- }
- } else
- vma->vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
- vma->vm_ops = NULL;
- vma->vm_offset = off;
- vma->vm_inode = NULL;
- vma->vm_pte = 0;
-
- do_munmap(addr, len); /* Clear old maps */
-
- if (file)
- error = file->f_op->mmap(file->f_inode, file, vma);
- else
- error = anon_map(NULL, NULL, vma);
-
- if (error) {
- kfree(vma);
- return error;
- }
- insert_vm_struct(current, vma);
- merge_segments(current->mm->mmap);
- return addr;
-}
-
-/*
- * Get an address range which is currently unmapped.
- * For mmap() without MAP_FIXED and shmat() with addr=0.
- * Return value 0 means ENOMEM.
- */
-unsigned long get_unmapped_area(unsigned long len)
-{
- struct vm_area_struct * vmm;
- unsigned long gap_start = 0, gap_end;
-
- for (vmm = current->mm->mmap; ; vmm = vmm->vm_next) {
- if (gap_start < SHM_RANGE_START)
- gap_start = SHM_RANGE_START;
- if (!vmm || ((gap_end = vmm->vm_start) > SHM_RANGE_END))
- gap_end = SHM_RANGE_END;
- gap_start = PAGE_ALIGN(gap_start);
- gap_end &= PAGE_MASK;
- if ((gap_start <= gap_end) && (gap_end - gap_start >= len))
- return gap_start;
- if (!vmm)
- return 0;
- gap_start = vmm->vm_end;
- }
-}
-
-asmlinkage int sys_mmap(unsigned long *buffer)
-{
- int error;
- unsigned long flags;
- struct file * file = NULL;
-
- error = verify_area(VERIFY_READ, buffer, 6*sizeof(long));
- if (error)
- return error;
- flags = get_fs_long(buffer+3);
- if (!(flags & MAP_ANONYMOUS)) {
- unsigned long fd = get_fs_long(buffer+4);
- if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
- return -EBADF;
- }
- return do_mmap(file, get_fs_long(buffer), get_fs_long(buffer+1),
- get_fs_long(buffer+2), flags, get_fs_long(buffer+5));
-}
-
-/*
- * Normal function to fix up a mapping
- * This function is the default for when an area has no specific
- * function. This may be used as part of a more specific routine.
- * This function works out what part of an area is affected and
- * adjusts the mapping information. Since the actual page
- * manipulation is done in do_mmap(), none need be done here,
- * though it would probably be more appropriate.
- *
- * By the time this function is called, the area struct has been
- * removed from the process mapping list, so it needs to be
- * reinserted if necessary.
- *
- * The 4 main cases are:
- * Unmapping the whole area
- * Unmapping from the start of the segment to a point in it
- * Unmapping from an intermediate point to the end
- * Unmapping between to intermediate points, making a hole.
- *
- * Case 4 involves the creation of 2 new areas, for each side of
- * the hole.
- */
-void unmap_fixup(struct vm_area_struct *area,
- unsigned long addr, size_t len)
-{
- struct vm_area_struct *mpnt;
- unsigned long end = addr + len;
-
- if (addr < area->vm_start || addr >= area->vm_end ||
- end <= area->vm_start || end > area->vm_end ||
- end < addr)
- {
- printk("unmap_fixup: area=%lx-%lx, unmap %lx-%lx!!\n",
- area->vm_start, area->vm_end, addr, end);
- return;
- }
-
- /* Unmapping the whole area */
- if (addr == area->vm_start && end == area->vm_end) {
- if (area->vm_ops && area->vm_ops->close)
- area->vm_ops->close(area);
- if (area->vm_inode)
- iput(area->vm_inode);
- return;
- }
-
- /* Work out to one of the ends */
- if (addr >= area->vm_start && end == area->vm_end)
- area->vm_end = addr;
- if (addr == area->vm_start && end <= area->vm_end) {
- area->vm_offset += (end - area->vm_start);
- area->vm_start = end;
- }
-
- /* Unmapping a hole */
- if (addr > area->vm_start && end < area->vm_end)
- {
- /* Add end mapping -- leave beginning for below */
- mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
-
- if (!mpnt)
- return;
- *mpnt = *area;
- mpnt->vm_offset += (end - area->vm_start);
- mpnt->vm_start = end;
- if (mpnt->vm_inode)
- mpnt->vm_inode->i_count++;
- if (mpnt->vm_ops && mpnt->vm_ops->open)
- mpnt->vm_ops->open(mpnt);
- area->vm_end = addr; /* Truncate area */
- insert_vm_struct(current, mpnt);
- }
-
- /* construct whatever mapping is needed */
- mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
- if (!mpnt)
- return;
- *mpnt = *area;
- if (mpnt->vm_ops && mpnt->vm_ops->open)
- mpnt->vm_ops->open(mpnt);
- if (area->vm_ops && area->vm_ops->close) {
- area->vm_end = area->vm_start;
- area->vm_ops->close(area);
- }
- insert_vm_struct(current, mpnt);
-}
-
-asmlinkage int sys_munmap(unsigned long addr, size_t len)
-{
- return do_munmap(addr, len);
-}
-
-/*
- * Munmap is split into 2 main parts -- this part which finds
- * what needs doing, and the areas themselves, which do the
- * work. This now handles partial unmappings.
- * Jeremy Fitzhardine <jeremy@sw.oz.au>
- */
-int do_munmap(unsigned long addr, size_t len)
-{
- struct vm_area_struct *mpnt, **npp, *free;
-
- if ((addr & ~PAGE_MASK) || addr > TASK_SIZE || len > TASK_SIZE-addr)
- return -EINVAL;
-
- if ((len = PAGE_ALIGN(len)) == 0)
- return 0;
-
- /*
- * Check if this memory area is ok - put it on the temporary
- * list if so.. The checks here are pretty simple --
- * every area affected in some way (by any overlap) is put
- * on the list. If nothing is put on, nothing is affected.
- */
- npp = &current->mm->mmap;
- free = NULL;
- for (mpnt = *npp; mpnt != NULL; mpnt = *npp) {
- unsigned long end = addr+len;
-
- if ((addr < mpnt->vm_start && end <= mpnt->vm_start) ||
- (addr >= mpnt->vm_end && end > mpnt->vm_end))
- {
- npp = &mpnt->vm_next;
- continue;
- }
-
- *npp = mpnt->vm_next;
- mpnt->vm_next = free;
- free = mpnt;
- }
-
- if (free == NULL)
- return 0;
-
- /*
- * Ok - we have the memory areas we should free on the 'free' list,
- * so release them, and unmap the page range..
- * If the one of the segments is only being partially unmapped,
- * it will put new vm_area_struct(s) into the address space.
- */
- while (free) {
- unsigned long st, end;
-
- mpnt = free;
- free = free->vm_next;
-
- st = addr < mpnt->vm_start ? mpnt->vm_start : addr;
- end = addr+len;
- end = end > mpnt->vm_end ? mpnt->vm_end : end;
-
- if (mpnt->vm_ops && mpnt->vm_ops->unmap)
- mpnt->vm_ops->unmap(mpnt, st, end-st);
- else
- unmap_fixup(mpnt, st, end-st);
-
- kfree(mpnt);
- }
-
- unmap_page_range(addr, len);
- return 0;
-}
-
-/* This is used for a general mmap of a disk file */
-int generic_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
-{
- extern struct vm_operations_struct file_mmap;
-
- if (vma->vm_page_prot & PAGE_RW) /* only PAGE_COW or read-only supported right now */
- return -EINVAL;
- if (vma->vm_offset & (inode->i_sb->s_blocksize - 1))
- return -EINVAL;
- if (!inode->i_sb || !S_ISREG(inode->i_mode))
- return -EACCES;
- if (!inode->i_op || !inode->i_op->bmap)
- return -ENOEXEC;
- if (!IS_RDONLY(inode)) {
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
- }
- vma->vm_inode = inode;
- inode->i_count++;
- vma->vm_ops = &file_mmap;
- return 0;
-}
-
-/*
- * Insert vm structure into process list sorted by address.
- */
-void insert_vm_struct(struct task_struct *t, struct vm_area_struct *vmp)
-{
- struct vm_area_struct **p, *mpnt;
-
- p = &t->mm->mmap;
- while ((mpnt = *p) != NULL) {
- if (mpnt->vm_start > vmp->vm_start)
- break;
- if (mpnt->vm_end > vmp->vm_start)
- printk("insert_vm_struct: overlapping memory areas\n");
- p = &mpnt->vm_next;
- }
- vmp->vm_next = mpnt;
- *p = vmp;
-}
-
-/*
- * Merge a list of memory segments if possible.
- * Redundant vm_area_structs are freed.
- * This assumes that the list is ordered by address.
- */
-void merge_segments(struct vm_area_struct *mpnt)
-{
- struct vm_area_struct *prev, *next;
-
- if (mpnt == NULL)
- return;
-
- for(prev = mpnt, mpnt = mpnt->vm_next;
- mpnt != NULL;
- prev = mpnt, mpnt = next)
- {
- next = mpnt->vm_next;
-
- /*
- * To share, we must have the same inode, operations..
- */
- if (mpnt->vm_inode != prev->vm_inode)
- continue;
- if (mpnt->vm_pte != prev->vm_pte)
- continue;
- if (mpnt->vm_ops != prev->vm_ops)
- continue;
- if (mpnt->vm_page_prot != prev->vm_page_prot ||
- mpnt->vm_flags != prev->vm_flags)
- continue;
- if (prev->vm_end != mpnt->vm_start)
- continue;
- /*
- * and if we have an inode, the offsets must be contiguous..
- */
- if ((mpnt->vm_inode != NULL) || (mpnt->vm_flags & VM_SHM)) {
- if (prev->vm_offset + prev->vm_end - prev->vm_start != mpnt->vm_offset)
- continue;
- }
-
- /*
- * merge prev with mpnt and set up pointers so the new
- * big segment can possibly merge with the next one.
- * The old unused mpnt is freed.
- */
- prev->vm_end = mpnt->vm_end;
- prev->vm_next = mpnt->vm_next;
- if (mpnt->vm_ops && mpnt->vm_ops->close) {
- mpnt->vm_offset += mpnt->vm_end - mpnt->vm_start;
- mpnt->vm_start = mpnt->vm_end;
- mpnt->vm_ops->close(mpnt);
- }
- if (mpnt->vm_inode)
- mpnt->vm_inode->i_count--;
- kfree_s(mpnt, sizeof(*mpnt));
- mpnt = prev;
- }
-}
-
-/*
- * Map memory not associated with any file into a process
- * address space. Adjacent memory is merged.
- */
-static int anon_map(struct inode *ino, struct file * file, struct vm_area_struct * vma)
-{
- if (zeromap_page_range(vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot))
- return -ENOMEM;
- return 0;
-}
diff --git a/arch/mips/mm/mprotect.c b/arch/mips/mm/mprotect.c
deleted file mode 100644
index 7bb4148f4..000000000
--- a/arch/mips/mm/mprotect.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * linux/mm/mprotect.c
- *
- * (C) Copyright 1994 Linus Torvalds
- */
-#include <linux/stat.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/shm.h>
-#include <linux/errno.h>
-#include <linux/mman.h>
-#include <linux/string.h>
-#include <linux/malloc.h>
-
-#include <asm/segment.h>
-#include <asm/system.h>
-
-#define CHG_MASK (PAGE_MASK | PAGE_ACCESSED | PAGE_DIRTY | CACHE_UNCACHED)
-
-static void change_protection(unsigned long start, unsigned long end, int prot)
-{
- unsigned long *page_table, *dir;
- unsigned long page, offset;
- int nr;
-
- dir = PAGE_DIR_OFFSET(current->tss.pg_dir, start);
- offset = (start >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
- nr = (end - start) >> PAGE_SHIFT;
- while (nr > 0) {
- page = *dir;
- dir++;
- if (!(page & PAGE_VALID)) {
- nr = nr - PTRS_PER_PAGE + offset;
- offset = 0;
- continue;
- }
- page_table = offset + (unsigned long *) (page & PAGE_MASK);
- offset = PTRS_PER_PAGE - offset;
- if (offset > nr)
- offset = nr;
- nr = nr - offset;
- do {
- page = *page_table;
- if (page & PAGE_VALID)
- *page_table = (page & CHG_MASK) | prot;
- ++page_table;
- } while (--offset);
- }
- return;
-}
-
-static inline int mprotect_fixup_all(struct vm_area_struct * vma,
- int newflags, int prot)
-{
- vma->vm_flags = newflags;
- vma->vm_page_prot = prot;
- return 0;
-}
-
-static inline int mprotect_fixup_start(struct vm_area_struct * vma,
- unsigned long end,
- int newflags, int prot)
-{
- struct vm_area_struct * n;
-
- n = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
- if (!n)
- return -ENOMEM;
- *n = *vma;
- vma->vm_start = end;
- n->vm_end = end;
- vma->vm_offset += vma->vm_start - n->vm_start;
- n->vm_flags = newflags;
- n->vm_page_prot = prot;
- if (n->vm_inode)
- n->vm_inode->i_count++;
- if (n->vm_ops && n->vm_ops->open)
- n->vm_ops->open(n);
- insert_vm_struct(current, n);
- return 0;
-}
-
-static inline int mprotect_fixup_end(struct vm_area_struct * vma,
- unsigned long start,
- int newflags, int prot)
-{
- struct vm_area_struct * n;
-
- n = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
- if (!n)
- return -ENOMEM;
- *n = *vma;
- vma->vm_end = start;
- n->vm_start = start;
- n->vm_offset += n->vm_start - vma->vm_start;
- n->vm_flags = newflags;
- n->vm_page_prot = prot;
- if (n->vm_inode)
- n->vm_inode->i_count++;
- if (n->vm_ops && n->vm_ops->open)
- n->vm_ops->open(n);
- insert_vm_struct(current, n);
- return 0;
-}
-
-static inline int mprotect_fixup_middle(struct vm_area_struct * vma,
- unsigned long start, unsigned long end,
- int newflags, int prot)
-{
- struct vm_area_struct * left, * right;
-
- left = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
- if (!left)
- return -ENOMEM;
- right = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
- if (!right) {
- kfree(left);
- return -ENOMEM;
- }
- *left = *vma;
- *right = *vma;
- left->vm_end = start;
- vma->vm_start = start;
- vma->vm_end = end;
- right->vm_start = end;
- vma->vm_offset += vma->vm_start - left->vm_start;
- right->vm_offset += right->vm_start - left->vm_start;
- vma->vm_flags = newflags;
- vma->vm_page_prot = prot;
- if (vma->vm_inode)
- vma->vm_inode->i_count += 2;
- if (vma->vm_ops && vma->vm_ops->open) {
- vma->vm_ops->open(left);
- vma->vm_ops->open(right);
- }
- insert_vm_struct(current, left);
- insert_vm_struct(current, right);
- return 0;
-}
-
-static int mprotect_fixup(struct vm_area_struct * vma,
- unsigned long start, unsigned long end, unsigned int newflags)
-{
- int prot, error;
-
- if (newflags == vma->vm_flags)
- return 0;
- prot = PAGE_VALID;
- if (newflags & (VM_READ | VM_EXEC))
- prot |= PAGE_READONLY;
- if (newflags & VM_WRITE)
- if (newflags & VM_SHARED)
- prot |= PAGE_SHARED;
- else
- prot |= PAGE_COPY;
-
- if (start == vma->vm_start)
- if (end == vma->vm_end)
- error = mprotect_fixup_all(vma, newflags, prot);
- else
- error = mprotect_fixup_start(vma, end, newflags, prot);
- else if (end == vma->vm_end)
- error = mprotect_fixup_end(vma, start, newflags, prot);
- else
- error = mprotect_fixup_middle(vma, start, end, newflags, prot);
-
- if (error)
- return error;
-
- change_protection(start, end, prot);
- return 0;
-}
-
-asmlinkage int sys_mprotect(unsigned long start, size_t len, unsigned long prot)
-{
- unsigned long end, tmp;
- struct vm_area_struct * vma, * next;
- int error;
-
- if (start & ~PAGE_MASK)
- return -EINVAL;
- len = (len + ~PAGE_MASK) & PAGE_MASK;
- end = start + len;
- if (end < start)
- return -EINVAL;
- if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
- return -EINVAL;
- if (end == start)
- return 0;
- for (vma = current->mm->mmap ; ; vma = vma->vm_next) {
- if (!vma)
- return -EFAULT;
- if (vma->vm_end > start)
- break;
- }
- if (vma->vm_start > start)
- return -EFAULT;
-
- for ( ; ; ) {
- unsigned int newflags;
-
- /* Here we know that vma->vm_start <= start < vma->vm_end. */
-
- newflags = prot | (vma->vm_flags & ~(PROT_READ | PROT_WRITE | PROT_EXEC));
- if ((newflags & ~(newflags >> 4)) & 0xf) {
- error = -EACCES;
- break;
- }
-
- if (vma->vm_end >= end) {
- error = mprotect_fixup(vma, start, end, newflags);
- break;
- }
-
- tmp = vma->vm_end;
- next = vma->vm_next;
- error = mprotect_fixup(vma, start, tmp, newflags);
- if (error)
- break;
- start = tmp;
- vma = next;
- if (!vma || vma->vm_start != start) {
- error = -EFAULT;
- break;
- }
- }
- merge_segments(current->mm->mmap);
- return error;
-}
diff --git a/arch/mips/mm/swap.c b/arch/mips/mm/swap.c
deleted file mode 100644
index 084208c04..000000000
--- a/arch/mips/mm/swap.c
+++ /dev/null
@@ -1,986 +0,0 @@
-/*
- * linux/mm/swap.c
- *
- * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
- */
-
-/*
- * This file should contain most things doing the swapping from/to disk.
- * Started 18.12.91
- */
-
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/head.h>
-#include <linux/kernel.h>
-#include <linux/kernel_stat.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/stat.h>
-#include <linux/fs.h>
-
-#include <asm/system.h> /* for cli()/sti() */
-#include <asm/bitops.h>
-
-#define MAX_SWAPFILES 8
-
-#define SWP_USED 1
-#define SWP_WRITEOK 3
-
-#define SWP_TYPE(entry) (((entry) & 0xfe) >> 1)
-#define SWP_OFFSET(entry) ((entry) >> PAGE_SHIFT)
-#define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << PAGE_SHIFT))
-
-int min_free_pages = 20;
-
-static int nr_swapfiles = 0;
-static struct wait_queue * lock_queue = NULL;
-
-static struct swap_info_struct {
- unsigned long flags;
- struct inode * swap_file;
- unsigned int swap_device;
- unsigned char * swap_map;
- unsigned char * swap_lockmap;
- int pages;
- int lowest_bit;
- int highest_bit;
- unsigned long max;
-} swap_info[MAX_SWAPFILES];
-
-extern int shm_swap (int);
-
-unsigned long *swap_cache;
-
-#ifdef SWAP_CACHE_INFO
-unsigned long swap_cache_add_total = 0;
-unsigned long swap_cache_add_success = 0;
-unsigned long swap_cache_del_total = 0;
-unsigned long swap_cache_del_success = 0;
-unsigned long swap_cache_find_total = 0;
-unsigned long swap_cache_find_success = 0;
-
-extern inline void show_swap_cache_info(void)
-{
- printk("Swap cache: add %ld/%ld, delete %ld/%ld, find %ld/%ld\n",
- swap_cache_add_total, swap_cache_add_success,
- swap_cache_del_total, swap_cache_del_success,
- swap_cache_find_total, swap_cache_find_success);
-}
-#endif
-
-extern inline int add_to_swap_cache(unsigned long addr, unsigned long entry)
-{
- struct swap_info_struct * p = &swap_info[SWP_TYPE(entry)];
-
-#ifdef SWAP_CACHE_INFO
- swap_cache_add_total++;
-#endif
- if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
- atomic_exchange(swap_cache[addr >> PAGE_SHIFT],entry);
- if (entry) {
- printk("swap_cache: replacing non-NULL entry\n");
- }
-#ifdef SWAP_CACHE_INFO
- swap_cache_add_success++;
-#endif
- return 1;
- }
- return 0;
-}
-
-static unsigned long init_swap_cache(unsigned long mem_start,
- unsigned long mem_end)
-{
- unsigned long swap_cache_size;
-
- mem_start = (mem_start + 15) & ~15;
- swap_cache = (unsigned long *) mem_start;
- swap_cache_size = mem_end >> PAGE_SHIFT;
- memset(swap_cache, 0, swap_cache_size * sizeof (unsigned long));
- return (unsigned long) (swap_cache + swap_cache_size);
-}
-
-void rw_swap_page(int rw, unsigned long entry, char * buf)
-{
- unsigned long type, offset;
- struct swap_info_struct * p;
-
- type = SWP_TYPE(entry);
- if (type >= nr_swapfiles) {
- printk("Internal error: bad swap-device\n");
- return;
- }
- p = &swap_info[type];
- offset = SWP_OFFSET(entry);
- if (offset >= p->max) {
- printk("rw_swap_page: weirdness\n");
- return;
- }
- if (!(p->flags & SWP_USED)) {
- printk("Trying to swap to unused swap-device\n");
- return;
- }
- while (set_bit(offset,p->swap_lockmap))
- sleep_on(&lock_queue);
- if (rw == READ)
- kstat.pswpin++;
- else
- kstat.pswpout++;
- if (p->swap_device) {
- ll_rw_page(rw,p->swap_device,offset,buf);
- } else if (p->swap_file) {
- struct inode *swapf = p->swap_file;
- unsigned int zones[8];
- int i;
- if (swapf->i_op->bmap == NULL
- && swapf->i_op->smap != NULL){
- /*
- With MsDOS, we use msdos_smap which return
- a sector number (not a cluster or block number).
- It is a patch to enable the UMSDOS project.
- Other people are working on better solution.
-
- It sounds like ll_rw_swap_file defined
- it operation size (sector size) based on
- PAGE_SIZE and the number of block to read.
- So using bmap or smap should work even if
- smap will require more blocks.
- */
- int j;
- unsigned int block = offset << 3;
-
- for (i=0, j=0; j< PAGE_SIZE ; i++, j += 512){
- if (!(zones[i] = swapf->i_op->smap(swapf,block++))) {
- printk("rw_swap_page: bad swap file\n");
- return;
- }
- }
- }else{
- int j;
- unsigned int block = offset
- << (12 - swapf->i_sb->s_blocksize_bits);
-
- for (i=0, j=0; j< PAGE_SIZE ; i++, j +=swapf->i_sb->s_blocksize)
- if (!(zones[i] = bmap(swapf,block++))) {
- printk("rw_swap_page: bad swap file\n");
- return;
- }
- }
- ll_rw_swap_file(rw,swapf->i_dev, zones, i,buf);
- } else
- printk("re_swap_page: no swap file or device\n");
- if (offset && !clear_bit(offset,p->swap_lockmap))
- printk("rw_swap_page: lock already cleared\n");
- wake_up(&lock_queue);
-}
-
-unsigned int get_swap_page(void)
-{
- struct swap_info_struct * p;
- unsigned int offset, type;
-
- p = swap_info;
- for (type = 0 ; type < nr_swapfiles ; type++,p++) {
- if ((p->flags & SWP_WRITEOK) != SWP_WRITEOK)
- continue;
- for (offset = p->lowest_bit; offset <= p->highest_bit ; offset++) {
- if (p->swap_map[offset])
- continue;
- p->swap_map[offset] = 1;
- nr_swap_pages--;
- if (offset == p->highest_bit)
- p->highest_bit--;
- p->lowest_bit = offset;
- return SWP_ENTRY(type,offset);
- }
- }
- return 0;
-}
-
-unsigned long swap_duplicate(unsigned long entry)
-{
- struct swap_info_struct * p;
- unsigned long offset, type;
-
- if (!entry)
- return 0;
- offset = SWP_OFFSET(entry);
- type = SWP_TYPE(entry);
- if (type == SHM_SWP_TYPE)
- return entry;
- if (type >= nr_swapfiles) {
- printk("Trying to duplicate nonexistent swap-page\n");
- return 0;
- }
- p = type + swap_info;
- if (offset >= p->max) {
- printk("swap_duplicate: weirdness\n");
- return 0;
- }
- if (!p->swap_map[offset]) {
- printk("swap_duplicate: trying to duplicate unused page\n");
- return 0;
- }
- p->swap_map[offset]++;
- return entry;
-}
-
-void swap_free(unsigned long entry)
-{
- struct swap_info_struct * p;
- unsigned long offset, type;
-
- if (!entry)
- return;
- type = SWP_TYPE(entry);
- if (type == SHM_SWP_TYPE)
- return;
- if (type >= nr_swapfiles) {
- printk("Trying to free nonexistent swap-page\n");
- return;
- }
- p = & swap_info[type];
- offset = SWP_OFFSET(entry);
- if (offset >= p->max) {
- printk("swap_free: weirdness\n");
- return;
- }
- if (!(p->flags & SWP_USED)) {
- printk("Trying to free swap from unused swap-device\n");
- return;
- }
- while (set_bit(offset,p->swap_lockmap))
- sleep_on(&lock_queue);
- if (offset < p->lowest_bit)
- p->lowest_bit = offset;
- if (offset > p->highest_bit)
- p->highest_bit = offset;
- if (!p->swap_map[offset])
- printk("swap_free: swap-space map bad (entry %08lx)\n",entry);
- else
- if (!--p->swap_map[offset])
- nr_swap_pages++;
- if (!clear_bit(offset,p->swap_lockmap))
- printk("swap_free: lock already cleared\n");
- wake_up(&lock_queue);
-}
-
-unsigned long swap_in(unsigned long entry)
-{
- unsigned long page;
-
- if (!(page = get_free_page(GFP_KERNEL))) {
- oom(current);
- return BAD_PAGE;
- }
- read_swap_page(entry, (char *) page);
- if (add_to_swap_cache(page, entry))
- return page | PAGE_VALID;
- swap_free(entry);
- return page | PAGE_DIRTY | PAGE_VALID;
-}
-
-static inline int try_to_swap_out(unsigned long * table_ptr)
-{
- unsigned long page, entry;
-
- page = *table_ptr;
- if (!(PAGE_VALID & page))
- return 0;
- if (page >= high_memory)
- return 0;
- if (mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED)
- return 0;
-
- if ((PAGE_DIRTY & page) && delete_from_swap_cache(page)) {
- *table_ptr &= ~PAGE_ACCESSED;
- return 0;
- }
- if (PAGE_ACCESSED & page) {
- *table_ptr &= ~PAGE_ACCESSED;
- return 0;
- }
- if (PAGE_DIRTY & page) {
- page &= PAGE_MASK;
- if (mem_map[MAP_NR(page)] != 1)
- return 0;
- if (!(entry = get_swap_page()))
- return 0;
- *table_ptr = entry;
- invalidate();
- write_swap_page(entry, (char *) page);
- free_page(page);
- return 1;
- }
- if ((entry = find_in_swap_cache(page))) {
- if (mem_map[MAP_NR(page)] != 1) {
- *table_ptr |= PAGE_DIRTY;
- printk("Aiee.. duplicated cached swap-cache entry\n");
- return 0;
- }
- *table_ptr = entry;
- invalidate();
- free_page(page & PAGE_MASK);
- return 1;
- }
- page &= PAGE_MASK;
- *table_ptr = 0;
- invalidate();
- free_page(page);
- return 1 + mem_map[MAP_NR(page)];
-}
-
-/*
- * A new implementation of swap_out(). We do not swap complete processes,
- * but only a small number of blocks, before we continue with the next
- * process. The number of blocks actually swapped is determined on the
- * number of page faults, that this process actually had in the last time,
- * so we won't swap heavily used processes all the time ...
- *
- * Note: the priority argument is a hint on much CPU to waste with the
- * swap block search, not a hint, of how much blocks to swap with
- * each process.
- *
- * (C) 1993 Kai Petzke, wpp@marie.physik.tu-berlin.de
- */
-
-/*
- * These are the minimum and maximum number of pages to swap from one process,
- * before proceeding to the next:
- */
-#define SWAP_MIN 4
-#define SWAP_MAX 32
-
-/*
- * The actual number of pages to swap is determined as:
- * SWAP_RATIO / (number of recent major page faults)
- */
-#define SWAP_RATIO 128
-
-static int swap_out_process(struct task_struct * p)
-{
- unsigned long address;
- unsigned long offset;
- unsigned long *pgdir;
- unsigned long pg_table;
-
- /*
- * Go through process' page directory.
- */
- address = p->mm->swap_address;
- pgdir = (address >> PGDIR_SHIFT) + (unsigned long *) p->tss.pg_dir;
- offset = address & ~PGDIR_MASK;
- address &= PGDIR_MASK;
- for ( ; address < TASK_SIZE ;
- pgdir++, address = address + PGDIR_SIZE, offset = 0) {
- pg_table = *pgdir;
- if (pg_table >= high_memory)
- continue;
- if (mem_map[MAP_NR(pg_table)] & MAP_PAGE_RESERVED)
- continue;
- if (!(PAGE_VALID & pg_table)) {
- printk("swap_out_process (%s): bad page-table at vm %08lx: %08lx\n",
- p->comm, address + offset, pg_table);
- *pgdir = 0;
- continue;
- }
- pg_table &= 0xfffff000;
-
- /*
- * Go through this page table.
- */
- for( ; offset < ~PGDIR_MASK ; offset += PAGE_SIZE) {
- switch(try_to_swap_out((unsigned long *) (pg_table + (offset >> 10)))) {
- case 0:
- break;
-
- case 1:
- p->mm->rss--;
- /* continue with the following page the next time */
- p->mm->swap_address = address + offset + PAGE_SIZE;
- return 1;
-
- default:
- p->mm->rss--;
- break;
- }
- }
- }
- /*
- * Finish work with this process, if we reached the end of the page
- * directory. Mark restart from the beginning the next time.
- */
- p->mm->swap_address = 0;
- return 0;
-}
-
-static int swap_out(unsigned int priority)
-{
- static int swap_task;
- int loop;
- int counter = NR_TASKS * 2 >> priority;
- struct task_struct *p;
-
- counter = NR_TASKS * 2 >> priority;
- for(; counter >= 0; counter--, swap_task++) {
- /*
- * Check that swap_task is suitable for swapping. If not, look for
- * the next suitable process.
- */
- loop = 0;
- while(1) {
- if (swap_task >= NR_TASKS) {
- swap_task = 1;
- if (loop)
- /* all processes are unswappable or already swapped out */
- return 0;
- loop = 1;
- }
-
- p = task[swap_task];
- if (p && p->mm->swappable && p->mm->rss)
- break;
-
- swap_task++;
- }
-
- /*
- * Determine the number of pages to swap from this process.
- */
- if (!p->mm->swap_cnt) {
- p->mm->dec_flt = (p->mm->dec_flt * 3) / 4 + p->mm->maj_flt - p->mm->old_maj_flt;
- p->mm->old_maj_flt = p->mm->maj_flt;
-
- if (p->mm->dec_flt >= SWAP_RATIO / SWAP_MIN) {
- p->mm->dec_flt = SWAP_RATIO / SWAP_MIN;
- p->mm->swap_cnt = SWAP_MIN;
- } else if (p->mm->dec_flt <= SWAP_RATIO / SWAP_MAX)
- p->mm->swap_cnt = SWAP_MAX;
- else
- p->mm->swap_cnt = SWAP_RATIO / p->mm->dec_flt;
- }
- if (swap_out_process(p)) {
- if ((--p->mm->swap_cnt) == 0)
- swap_task++;
- return 1;
- }
- }
- return 0;
-}
-
-static int try_to_free_page(int priority)
-{
- int i=6;
-
- while (i--) {
- if (priority != GFP_NOBUFFER && shrink_buffers(i))
- return 1;
- if (shm_swap(i))
- return 1;
- if (swap_out(i))
- return 1;
- }
- return 0;
-}
-
-static inline void add_mem_queue(struct mem_list * head, struct mem_list * entry)
-{
- entry->prev = head;
- entry->next = head->next;
- entry->next->prev = entry;
- head->next = entry;
-}
-
-static inline void remove_mem_queue(struct mem_list * head, struct mem_list * entry)
-{
- entry->next->prev = entry->prev;
- entry->prev->next = entry->next;
-}
-
-/*
- * Free_page() adds the page to the free lists. This is optimized for
- * fast normal cases (no error jumps taken normally).
- *
- * The way to optimize jumps for gcc-2.2.2 is to:
- * - select the "normal" case and put it inside the if () { XXX }
- * - no else-statements if you can avoid them
- *
- * With the above two rules, you get a straight-line execution path
- * for the normal case, giving better asm-code.
- */
-
-/*
- * Buddy system. Hairy. You really aren't expected to understand this
- */
-static inline void free_pages_ok(unsigned long addr, unsigned long order)
-{
- unsigned long index = addr >> (PAGE_SHIFT + 1 + order);
- unsigned long mask = PAGE_MASK << order;
-
- addr &= mask;
- nr_free_pages += 1 << order;
- while (order < NR_MEM_LISTS-1) {
- if (!change_bit(index, free_area_map[order]))
- break;
- remove_mem_queue(free_area_list+order, (struct mem_list *) (addr ^ (1+~mask)));
- order++;
- index >>= 1;
- mask <<= 1;
- addr &= mask;
- }
- add_mem_queue(free_area_list+order, (struct mem_list *) addr);
-}
-
-static inline void check_free_buffers(unsigned long addr)
-{
- struct buffer_head * bh;
-
- bh = buffer_pages[MAP_NR(addr)];
- if (bh) {
- struct buffer_head *tmp = bh;
- do {
- if (tmp->b_list == BUF_SHARED && tmp->b_dev != 0xffff)
- refile_buffer(tmp);
- tmp = tmp->b_this_page;
- } while (tmp != bh);
- }
-}
-
-void free_pages(unsigned long addr, unsigned long order)
-{
- if (addr < high_memory) {
- unsigned long flag;
- unsigned short * map = mem_map + MAP_NR(addr);
- if (*map) {
- if (!(*map & MAP_PAGE_RESERVED)) {
- save_flags(flag);
- cli();
- if (!--*map) {
- free_pages_ok(addr, order);
- delete_from_swap_cache(addr);
- }
- restore_flags(flag);
- if (*map == 1)
- check_free_buffers(addr);
- }
- return;
- }
- printk("Trying to free free memory (%08lx): memory probably corrupted\n",addr);
- printk("PC = %08lx\n",*(((unsigned long *)&addr)-1));
- return;
- }
-}
-
-/*
- * Some ugly macros to speed up __get_free_pages()..
- */
-#define RMQUEUE(order) \
-do { struct mem_list * queue = free_area_list+order; \
- unsigned long new_order = order; \
- do { struct mem_list *next = queue->next; \
- if (queue != next) { \
- (queue->next = next->next)->prev = queue; \
- mark_used((unsigned long) next, new_order); \
- nr_free_pages -= 1 << order; \
- restore_flags(flags); \
- EXPAND(next, order, new_order); \
- return (unsigned long) next; \
- } new_order++; queue++; \
- } while (new_order < NR_MEM_LISTS); \
-} while (0)
-
-static inline int mark_used(unsigned long addr, unsigned long order)
-{
- return change_bit(addr >> (PAGE_SHIFT+1+order), free_area_map[order]);
-}
-
-#define EXPAND(addr,low,high) \
-do { unsigned long size = PAGE_SIZE << high; \
- while (high > low) { \
- high--; size >>= 1; cli(); \
- add_mem_queue(free_area_list+high, addr); \
- mark_used((unsigned long) addr, high); \
- restore_flags(flags); \
- addr = (struct mem_list *) (size + (unsigned long) addr); \
- } mem_map[MAP_NR((unsigned long) addr)] = 1; \
-} while (0)
-
-unsigned long __get_free_pages(int priority, unsigned long order)
-{
- unsigned long flags;
- int reserved_pages;
-
- if (intr_count && priority != GFP_ATOMIC) {
- static int count = 0;
- if (++count < 5) {
- printk("gfp called nonatomically from interrupt %p\n",
- __builtin_return_address(0));
- priority = GFP_ATOMIC;
- }
- }
- reserved_pages = 5;
- if (priority != GFP_NFS)
- reserved_pages = min_free_pages;
- save_flags(flags);
-repeat:
- cli();
- if ((priority==GFP_ATOMIC) || nr_free_pages > reserved_pages) {
- RMQUEUE(order);
- restore_flags(flags);
- return 0;
- }
- restore_flags(flags);
- if (priority != GFP_BUFFER && try_to_free_page(priority))
- goto repeat;
- return 0;
-}
-
-/*
- * Yes, I know this is ugly. Don't tell me.
- */
-unsigned long __get_dma_pages(int priority, unsigned long order)
-{
- unsigned long list = 0;
- unsigned long result;
- unsigned long limit = 16*1024*1024;
-
- /* if (EISA_bus) limit = ~0UL; */
- if (priority != GFP_ATOMIC)
- priority = GFP_BUFFER;
- for (;;) {
- result = __get_free_pages(priority, order);
- if (result < limit) /* covers failure as well */
- break;
- *(unsigned long *) result = list;
- list = result;
- }
- while (list) {
- unsigned long tmp = list;
- list = *(unsigned long *) list;
- free_pages(tmp, order);
- }
- return result;
-}
-
-/*
- * Show free area list (used inside shift_scroll-lock stuff)
- * We also calculate the percentage fragmentation. We do this by counting the
- * memory on each free list with the exception of the first item on the list.
- */
-void show_free_areas(void)
-{
- unsigned long order, flags;
- unsigned long total = 0;
-
- printk("Free pages: %6dkB\n ( ",nr_free_pages<<(PAGE_SHIFT-10));
- save_flags(flags);
- cli();
- for (order=0 ; order < NR_MEM_LISTS; order++) {
- struct mem_list * tmp;
- unsigned long nr = 0;
- for (tmp = free_area_list[order].next ; tmp != free_area_list + order ; tmp = tmp->next) {
- nr ++;
- }
- total += nr * (4 << order);
- printk("%lu*%ukB ", nr, 4 << order);
- }
- restore_flags(flags);
- printk("= %lukB)\n", total);
-#ifdef SWAP_CACHE_INFO
- show_swap_cache_info();
-#endif
-}
-
-/*
- * Trying to stop swapping from a file is fraught with races, so
- * we repeat quite a bit here when we have to pause. swapoff()
- * isn't exactly timing-critical, so who cares?
- */
-static int try_to_unuse(unsigned int type)
-{
- int nr, pgt, pg;
- unsigned long page, *ppage;
- unsigned long tmp = 0;
- struct task_struct *p;
-
- nr = 0;
-
-/*
- * When we have to sleep, we restart the whole algorithm from the same
- * task we stopped in. That at least rids us of all races.
- */
-repeat:
- for (; nr < NR_TASKS ; nr++) {
- p = task[nr];
- if (!p)
- continue;
- for (pgt = 0 ; pgt < PTRS_PER_PAGE ; pgt++) {
- ppage = pgt + ((unsigned long *) p->tss.pg_dir);
- page = *ppage;
- if (!page)
- continue;
- if (!(page & PAGE_VALID) || (page >= high_memory))
- continue;
- if (mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED)
- continue;
- ppage = (unsigned long *) (page & PAGE_MASK);
- for (pg = 0 ; pg < PTRS_PER_PAGE ; pg++,ppage++) {
- page = *ppage;
- if (!page)
- continue;
- if (page & PAGE_VALID) {
- if (!(page = in_swap_cache(page)))
- continue;
- if (SWP_TYPE(page) != type)
- continue;
- *ppage |= PAGE_DIRTY;
- delete_from_swap_cache(*ppage);
- continue;
- }
- if (SWP_TYPE(page) != type)
- continue;
- if (!tmp) {
- if (!(tmp = __get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- goto repeat;
- }
- read_swap_page(page, (char *) tmp);
- if (*ppage == page) {
- *ppage = tmp | (PAGE_DIRTY | PAGE_PRIVATE);
- ++p->mm->rss;
- swap_free(page);
- tmp = 0;
- }
- goto repeat;
- }
- }
- }
- free_page(tmp);
- return 0;
-}
-
-asmlinkage int sys_swapoff(const char * specialfile)
-{
- struct swap_info_struct * p;
- struct inode * inode;
- unsigned int type;
- int i;
-
- if (!suser())
- return -EPERM;
- i = namei(specialfile,&inode);
- if (i)
- return i;
- p = swap_info;
- for (type = 0 ; type < nr_swapfiles ; type++,p++) {
- if ((p->flags & SWP_WRITEOK) != SWP_WRITEOK)
- continue;
- if (p->swap_file) {
- if (p->swap_file == inode)
- break;
- } else {
- if (!S_ISBLK(inode->i_mode))
- continue;
- if (p->swap_device == inode->i_rdev)
- break;
- }
- }
- iput(inode);
- if (type >= nr_swapfiles)
- return -EINVAL;
- p->flags = SWP_USED;
- i = try_to_unuse(type);
- if (i) {
- p->flags = SWP_WRITEOK;
- return i;
- }
- nr_swap_pages -= p->pages;
- iput(p->swap_file);
- p->swap_file = NULL;
- p->swap_device = 0;
- vfree(p->swap_map);
- p->swap_map = NULL;
- free_page((long) p->swap_lockmap);
- p->swap_lockmap = NULL;
- p->flags = 0;
- return 0;
-}
-
-/*
- * Written 01/25/92 by Simmule Turner, heavily changed by Linus.
- *
- * The swapon system call
- */
-asmlinkage int sys_swapon(const char * specialfile)
-{
- struct swap_info_struct * p;
- struct inode * swap_inode;
- unsigned int type;
- int i,j;
- int error;
-
- if (!suser())
- return -EPERM;
- p = swap_info;
- for (type = 0 ; type < nr_swapfiles ; type++,p++)
- if (!(p->flags & SWP_USED))
- break;
- if (type >= MAX_SWAPFILES)
- return -EPERM;
- if (type >= nr_swapfiles)
- nr_swapfiles = type+1;
- p->flags = SWP_USED;
- p->swap_file = NULL;
- p->swap_device = 0;
- p->swap_map = NULL;
- p->swap_lockmap = NULL;
- p->lowest_bit = 0;
- p->highest_bit = 0;
- p->max = 1;
- error = namei(specialfile,&swap_inode);
- if (error)
- goto bad_swap;
- p->swap_file = swap_inode;
- error = -EBUSY;
- if (swap_inode->i_count != 1)
- goto bad_swap;
- error = -EINVAL;
- if (S_ISBLK(swap_inode->i_mode)) {
- p->swap_device = swap_inode->i_rdev;
- p->swap_file = NULL;
- iput(swap_inode);
- error = -ENODEV;
- if (!p->swap_device)
- goto bad_swap;
- error = -EBUSY;
- for (i = 0 ; i < nr_swapfiles ; i++) {
- if (i == type)
- continue;
- if (p->swap_device == swap_info[i].swap_device)
- goto bad_swap;
- }
- } else if (!S_ISREG(swap_inode->i_mode))
- goto bad_swap;
- p->swap_lockmap = (unsigned char *) get_free_page(GFP_USER);
- if (!p->swap_lockmap) {
- printk("Unable to start swapping: out of memory :-)\n");
- error = -ENOMEM;
- goto bad_swap;
- }
- read_swap_page(SWP_ENTRY(type,0), (char *) p->swap_lockmap);
- if (memcmp("SWAP-SPACE",p->swap_lockmap+4086,10)) {
- printk("Unable to find swap-space signature\n");
- error = -EINVAL;
- goto bad_swap;
- }
- memset(p->swap_lockmap+PAGE_SIZE-10,0,10);
- j = 0;
- p->lowest_bit = 0;
- p->highest_bit = 0;
- for (i = 1 ; i < 8*PAGE_SIZE ; i++) {
- if (test_bit(i,p->swap_lockmap)) {
- if (!p->lowest_bit)
- p->lowest_bit = i;
- p->highest_bit = i;
- p->max = i+1;
- j++;
- }
- }
- if (!j) {
- printk("Empty swap-file\n");
- error = -EINVAL;
- goto bad_swap;
- }
- p->swap_map = (unsigned char *) vmalloc(p->max);
- if (!p->swap_map) {
- error = -ENOMEM;
- goto bad_swap;
- }
- for (i = 1 ; i < p->max ; i++) {
- if (test_bit(i,p->swap_lockmap))
- p->swap_map[i] = 0;
- else
- p->swap_map[i] = 0x80;
- }
- p->swap_map[0] = 0x80;
- memset(p->swap_lockmap,0,PAGE_SIZE);
- p->flags = SWP_WRITEOK;
- p->pages = j;
- nr_swap_pages += j;
- printk("Adding Swap: %dk swap-space\n",j<<2);
- return 0;
-bad_swap:
- free_page((long) p->swap_lockmap);
- vfree(p->swap_map);
- iput(p->swap_file);
- p->swap_device = 0;
- p->swap_file = NULL;
- p->swap_map = NULL;
- p->swap_lockmap = NULL;
- p->flags = 0;
- return error;
-}
-
-void si_swapinfo(struct sysinfo *val)
-{
- unsigned int i, j;
-
- val->freeswap = val->totalswap = 0;
- for (i = 0; i < nr_swapfiles; i++) {
- if ((swap_info[i].flags & SWP_WRITEOK) != SWP_WRITEOK)
- continue;
- for (j = 0; j < swap_info[i].max; ++j)
- switch (swap_info[i].swap_map[j]) {
- case 128:
- continue;
- case 0:
- ++val->freeswap;
- default:
- ++val->totalswap;
- }
- }
- val->freeswap <<= PAGE_SHIFT;
- val->totalswap <<= PAGE_SHIFT;
- return;
-}
-
-/*
- * set up the free-area data structures:
- * - mark all pages MAP_PAGE_RESERVED
- * - mark all memory queues empty
- * - clear the memory bitmaps
- */
-unsigned long free_area_init(unsigned long start_mem, unsigned long end_mem)
-{
- unsigned short * p;
- unsigned long mask = PAGE_MASK;
- int i;
-
- /*
- * select nr of pages we try to keep free for important stuff
- * with a minimum of 16 pages. This is totally arbitrary
- */
- i = end_mem >> (PAGE_SHIFT+6);
- if (i < 16)
- i = 16;
- min_free_pages = i;
- start_mem = init_swap_cache(start_mem, end_mem);
- mem_map = (unsigned short *) start_mem;
- p = mem_map + MAP_NR(end_mem);
- start_mem = (unsigned long) p;
- while (p > mem_map)
- *--p = MAP_PAGE_RESERVED;
-
- for (i = 0 ; i < NR_MEM_LISTS ; i++, mask <<= 1) {
- unsigned long bitmap_size;
- free_area_list[i].prev = free_area_list[i].next = &free_area_list[i];
- end_mem = (end_mem + ~mask) & mask;
- bitmap_size = end_mem >> (PAGE_SHIFT + i);
- bitmap_size = (bitmap_size + 7) >> 3;
- free_area_map[i] = (unsigned char *) start_mem;
- memset((void *) start_mem, 0, bitmap_size);
- start_mem += bitmap_size;
- }
- return start_mem;
-}
diff --git a/arch/mips/mm/vmalloc.c b/arch/mips/mm/vmalloc.c
deleted file mode 100644
index 9b3ab7f59..000000000
--- a/arch/mips/mm/vmalloc.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * linux/mm/vmalloc.c
- *
- * Copyright (C) 1993 Linus Torvalds
- */
-
-#include <asm/system.h>
-#include <linux/config.h>
-
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/head.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/malloc.h>
-#include <asm/segment.h>
-
-struct vm_struct {
- unsigned long flags;
- void * addr;
- unsigned long size;
- struct vm_struct * next;
-};
-
-static struct vm_struct * vmlist = NULL;
-
-/* Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts. That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-#define VMALLOC_OFFSET (8*1024*1024)
-
-static inline void set_pgdir(unsigned long dindex, unsigned long value)
-{
- struct task_struct * p;
-
- p = &init_task;
- do {
- ((unsigned long *) p->tss.pg_dir)[dindex] = value;
- p = p->next_task;
- } while (p != &init_task);
-}
-
-static int free_area_pages(unsigned long dindex, unsigned long index, unsigned long nr)
-{
- unsigned long page, *pte;
-
- if (!(PAGE_VALID & (page = swapper_pg_dir[dindex])))
- return 0;
- page &= PAGE_MASK;
- pte = index + (unsigned long *) page;
- do {
- unsigned long pg = *pte;
- *pte = 0;
- if (pg & PAGE_VALID)
- free_page(pg);
- pte++;
- } while (--nr);
- pte = (unsigned long *) page;
- for (nr = 0 ; nr < 1024 ; nr++, pte++)
- if (*pte)
- return 0;
- set_pgdir(dindex,0);
- mem_map[MAP_NR(page)] = 1;
- free_page(page);
- invalidate();
- return 0;
-}
-
-static int alloc_area_pages(unsigned long dindex, unsigned long index, unsigned long nr)
-{
- unsigned long page, *pte;
-
- page = swapper_pg_dir[dindex];
- if (!page) {
- page = get_free_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;
- if (swapper_pg_dir[dindex]) {
- free_page(page);
- page = swapper_pg_dir[dindex];
- } else {
- mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED;
- set_pgdir(dindex, page | PAGE_SHARED);
- }
- }
- page &= PAGE_MASK;
- pte = index + (unsigned long *) page;
- *pte = PAGE_SHARED; /* remove a race with vfree() */
- do {
- unsigned long pg = get_free_page(GFP_KERNEL);
-
- if (!pg)
- return -ENOMEM;
- *pte = pg | PAGE_SHARED;
- pte++;
- } while (--nr);
- invalidate();
- return 0;
-}
-
-static int do_area(void * addr, unsigned long size,
- int (*area_fn)(unsigned long,unsigned long,unsigned long))
-{
- unsigned long nr, dindex, index;
-
- nr = size >> PAGE_SHIFT;
- dindex = (TASK_SIZE + (unsigned long) addr) >> 22;
- index = (((unsigned long) addr) >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
- while (nr > 0) {
- unsigned long i = PTRS_PER_PAGE - index;
-
- if (i > nr)
- i = nr;
- nr -= i;
- if (area_fn(dindex, index, i))
- return -1;
- index = 0;
- dindex++;
- }
- return 0;
-}
-
-void vfree(void * addr)
-{
- struct vm_struct **p, *tmp;
-
- if (!addr)
- return;
- if ((PAGE_SIZE-1) & (unsigned long) addr) {
- printk("Trying to vfree() bad address (%p)\n", addr);
- return;
- }
- for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) {
- if (tmp->addr == addr) {
- *p = tmp->next;
- do_area(tmp->addr, tmp->size, free_area_pages);
- kfree(tmp);
- return;
- }
- }
- printk("Trying to vfree() nonexistent vm area (%p)\n", addr);
-}
-
-void * vmalloc(unsigned long size)
-{
- void * addr;
- struct vm_struct **p, *tmp, *area;
-
- size = PAGE_ALIGN(size);
- if (!size || size > high_memory)
- return NULL;
- area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
- if (!area)
- return NULL;
- addr = (void *) ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1));
- area->size = size + PAGE_SIZE;
- area->next = NULL;
- for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
- if (size + (unsigned long) addr < (unsigned long) tmp->addr)
- break;
- addr = (void *) (tmp->size + (unsigned long) tmp->addr);
- }
- area->addr = addr;
- area->next = *p;
- *p = area;
- if (do_area(addr, size, alloc_area_pages)) {
- vfree(addr);
- return NULL;
- }
- return addr;
-}
-
-int vread(char *buf, char *addr, int count)
-{
- struct vm_struct **p, *tmp;
- char *vaddr, *buf_start = buf;
- int n;
-
- for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
- vaddr = (char *) tmp->addr;
- while (addr < vaddr) {
- if (count == 0)
- goto finished;
- put_fs_byte('\0', buf++), addr++, count--;
- }
- n = tmp->size - PAGE_SIZE;
- if (addr > vaddr)
- n -= addr - vaddr;
- while (--n >= 0) {
- if (count == 0)
- goto finished;
- put_fs_byte(*addr++, buf++), count--;
- }
- }
-finished:
- return buf - buf_start;
-}
diff --git a/arch/mips/sched.c b/arch/mips/sched.c
deleted file mode 100644
index 5c60764a8..000000000
--- a/arch/mips/sched.c
+++ /dev/null
@@ -1,804 +0,0 @@
-/*
- * linux/kernel/sched.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- */
-
-/*
- * 'sched.c' is the main kernel file. It contains scheduling primitives
- * (sleep_on, wakeup, schedule etc) as well as a number of simple system
- * call functions (type getpid(), which just extracts a field from
- * current-task
- */
-
-#include <linux/config.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/kernel.h>
-#include <linux/kernel_stat.h>
-#include <linux/fdreg.h>
-#include <linux/errno.h>
-#include <linux/time.h>
-#include <linux/ptrace.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/tqueue.h>
-#include <linux/resource.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/segment.h>
-
-#define TIMER_IRQ 0
-
-#include <linux/timex.h>
-
-/*
- * kernel variables
- */
-long tick = 1000000 / HZ; /* timer interrupt period */
-volatile struct timeval xtime; /* The current time */
-int tickadj = 500/HZ; /* microsecs */
-
-DECLARE_TASK_QUEUE(tq_timer);
-DECLARE_TASK_QUEUE(tq_immediate);
-
-/*
- * phase-lock loop variables
- */
-int time_status = TIME_BAD; /* clock synchronization status */
-long time_offset = 0; /* time adjustment (us) */
-long time_constant = 0; /* pll time constant */
-long time_tolerance = MAXFREQ; /* frequency tolerance (ppm) */
-long time_precision = 1; /* clock precision (us) */
-long time_maxerror = 0x70000000;/* maximum error */
-long time_esterror = 0x70000000;/* estimated error */
-long time_phase = 0; /* phase offset (scaled us) */
-long time_freq = 0; /* frequency offset (scaled ppm) */
-long time_adj = 0; /* tick adjust (scaled 1 / HZ) */
-long time_reftime = 0; /* time at last adjustment (s) */
-
-long time_adjust = 0;
-long time_adjust_step = 0;
-
-int need_resched = 0;
-unsigned long event = 0;
-
-/*
- * Tell us the machine setup..
- */
-int hard_math = 0; /* set by boot/head.S */
-int wp_works_ok = 0; /* set if paging hardware honours WP */
-
-/*
- * Bus types ..
- */
-int EISA_bus = 0;
-
-extern int _setitimer(int, struct itimerval *, struct itimerval *);
-unsigned long * prof_buffer = NULL;
-unsigned long prof_len = 0;
-
-#define _S(nr) (1<<((nr)-1))
-
-extern void mem_use(void);
-
-extern int timer_interrupt(void);
-asmlinkage int system_call(void);
-
-static unsigned long init_kernel_stack[1024] = { STACK_MAGIC, };
-static struct vm_area_struct init_mmap = INIT_MMAP;
-struct task_struct init_task = INIT_TASK;
-
-unsigned long volatile jiffies=0;
-
-struct task_struct *current = &init_task;
-struct task_struct *last_task_used_math = NULL;
-
-struct task_struct * task[NR_TASKS] = {&init_task, };
-
-long user_stack [ PAGE_SIZE>>2 ] = { STACK_MAGIC, };
-
-struct kernel_stat kstat = { 0 };
-
-#ifndef CONFIG_MATH_EMULATION
-
-/*
- * FIXME: There is no fpa emulator yet
- */
-asmlinkage void math_emulate(long arg)
-{
- printk("math-emulation not enabled and no coprocessor found.\n");
- printk("killing %s.\n",current->comm);
- send_sig(SIGFPE,current,1);
- schedule();
-}
-
-#endif /* CONFIG_MATH_EMULATION */
-
-unsigned long itimer_ticks = 0;
-unsigned long itimer_next = ~0;
-
-/*
- * 'schedule()' is the scheduler function. It's a very simple and nice
- * scheduler: it's not perfect, but certainly works for most things.
- * The one thing you might take a look at is the signal-handler code here.
- *
- * NOTE!! Task 0 is the 'idle' task, which gets called when no other
- * tasks can run. It can not be killed, and it cannot sleep. The 'state'
- * information in task[0] is never used.
- *
- * The "confuse_gcc" goto is used only to get better assembly code..
- * Dijkstra probably hates me.
- */
-asmlinkage void schedule(void)
-{
- int c;
- struct task_struct * p;
- struct task_struct * next;
- unsigned long ticks;
-
- /*
- * check alarm, wake up any interruptible tasks that have got a signal
- */
- if (intr_count) {
- printk("Aiee: scheduling in interrupt\n");
- intr_count = 0;
- }
- cli();
- ticks = itimer_ticks;
- itimer_ticks = 0;
- itimer_next = ~0;
- sti();
- need_resched = 0;
- p = &init_task;
- for (;;) {
- if ((p = p->next_task) == &init_task)
- goto confuse_gcc1;
- if (ticks && p->it_real_value) {
- if (p->it_real_value <= ticks) {
- send_sig(SIGALRM, p, 1);
- if (!p->it_real_incr) {
- p->it_real_value = 0;
- goto end_itimer;
- }
- do {
- p->it_real_value += p->it_real_incr;
- } while (p->it_real_value <= ticks);
- }
- p->it_real_value -= ticks;
- if (p->it_real_value < itimer_next)
- itimer_next = p->it_real_value;
- }
-end_itimer:
- if (p->state != TASK_INTERRUPTIBLE)
- continue;
- if (p->signal & ~p->blocked) {
- p->state = TASK_RUNNING;
- continue;
- }
- if (p->timeout && p->timeout <= jiffies) {
- p->timeout = 0;
- p->state = TASK_RUNNING;
- }
- }
-confuse_gcc1:
-
-/* this is the scheduler proper: */
-#if 0
- /* give processes that go to sleep a bit higher priority.. */
- /* This depends on the values for TASK_XXX */
- /* This gives smoother scheduling for some things, but */
- /* can be very unfair under some circumstances, so.. */
- if (TASK_UNINTERRUPTIBLE >= (unsigned) current->state &&
- current->counter < current->priority*2) {
- ++current->counter;
- }
-#endif
- c = -1000;
- next = p = &init_task;
- for (;;) {
- if ((p = p->next_task) == &init_task)
- goto confuse_gcc2;
- if (p->state == TASK_RUNNING && p->counter > c)
- c = p->counter, next = p;
- }
-confuse_gcc2:
- if (!c) {
- for_each_task(p)
- p->counter = (p->counter >> 1) + p->priority;
- }
- if (current == next)
- return;
- kstat.context_swtch++;
- switch_to(next);
-}
-
-asmlinkage int sys_pause(void)
-{
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- return -ERESTARTNOHAND;
-}
-
-/*
- * wake_up doesn't wake up stopped processes - they have to be awakened
- * with signals or similar.
- *
- * Note that this doesn't need cli-sti pairs: interrupts may not change
- * the wait-queue structures directly, but only call wake_up() to wake
- * a process. The process itself must remove the queue once it has woken.
- */
-void wake_up(struct wait_queue **q)
-{
- struct wait_queue *tmp;
- struct task_struct * p;
-
- if (!q || !(tmp = *q))
- return;
- do {
- if ((p = tmp->task) != NULL) {
- if ((p->state == TASK_UNINTERRUPTIBLE) ||
- (p->state == TASK_INTERRUPTIBLE)) {
- p->state = TASK_RUNNING;
- if (p->counter > current->counter + 3)
- need_resched = 1;
- }
- }
- if (!tmp->next) {
- printk("wait_queue is bad (pc = %p)\n",
- __builtin_return_address(0));
- printk(" q = %p\n",q);
- printk(" *q = %p\n",*q);
- printk(" tmp = %p\n",tmp);
- break;
- }
- tmp = tmp->next;
- } while (tmp != *q);
-}
-
-void wake_up_interruptible(struct wait_queue **q)
-{
- struct wait_queue *tmp;
- struct task_struct * p;
-
- if (!q || !(tmp = *q))
- return;
- do {
- if ((p = tmp->task) != NULL) {
- if (p->state == TASK_INTERRUPTIBLE) {
- p->state = TASK_RUNNING;
- if (p->counter > current->counter + 3)
- need_resched = 1;
- }
- }
- if (!tmp->next) {
- printk("wait_queue is bad (eip = %p)\n",
- __builtin_return_address(0));
- printk(" q = %p\n",q);
- printk(" *q = %p\n",*q);
- printk(" tmp = %p\n",tmp);
- break;
- }
- tmp = tmp->next;
- } while (tmp != *q);
-}
-
-void __down(struct semaphore * sem)
-{
- struct wait_queue wait = { current, NULL };
- add_wait_queue(&sem->wait, &wait);
- current->state = TASK_UNINTERRUPTIBLE;
- while (sem->count <= 0) {
- schedule();
- current->state = TASK_UNINTERRUPTIBLE;
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&sem->wait, &wait);
-}
-
-static inline void __sleep_on(struct wait_queue **p, int state)
-{
- unsigned long flags;
- struct wait_queue wait = { current, NULL };
-
- if (!p)
- return;
- if (current == task[0])
- panic("task[0] trying to sleep");
- current->state = state;
- add_wait_queue(p, &wait);
- save_flags(flags);
- sti();
- schedule();
- remove_wait_queue(p, &wait);
- restore_flags(flags);
-}
-
-void interruptible_sleep_on(struct wait_queue **p)
-{
- __sleep_on(p,TASK_INTERRUPTIBLE);
-}
-
-void sleep_on(struct wait_queue **p)
-{
- __sleep_on(p,TASK_UNINTERRUPTIBLE);
-}
-
-/*
- * The head for the timer-list has a "expires" field of MAX_UINT,
- * and the sorting routine counts on this..
- */
-static struct timer_list timer_head = { &timer_head, &timer_head, ~0, 0, NULL };
-#define SLOW_BUT_DEBUGGING_TIMERS 1
-
-void add_timer(struct timer_list * timer)
-{
- unsigned long flags;
- struct timer_list *p;
-
-#if SLOW_BUT_DEBUGGING_TIMERS
- if (timer->next || timer->prev) {
- printk("add_timer() called with non-zero list from %p\n",
- __builtin_return_address(0));
- return;
- }
-#endif
- p = &timer_head;
- timer->expires += jiffies;
- save_flags(flags);
- cli();
- do {
- p = p->next;
- } while (timer->expires > p->expires);
- timer->next = p;
- timer->prev = p->prev;
- p->prev = timer;
- timer->prev->next = timer;
- restore_flags(flags);
-}
-
-int del_timer(struct timer_list * timer)
-{
- unsigned long flags;
-#if SLOW_BUT_DEBUGGING_TIMERS
- struct timer_list * p;
-
- p = &timer_head;
- save_flags(flags);
- cli();
- while ((p = p->next) != &timer_head) {
- if (p == timer) {
- timer->next->prev = timer->prev;
- timer->prev->next = timer->next;
- timer->next = timer->prev = NULL;
- restore_flags(flags);
- timer->expires -= jiffies;
- return 1;
- }
- }
- if (timer->next || timer->prev)
- printk("del_timer() called from %p with timer not initialized\n",
- __builtin_return_address(0));
- restore_flags(flags);
- return 0;
-#else
- save_flags(flags);
- cli();
- if (timer->next) {
- timer->next->prev = timer->prev;
- timer->prev->next = timer->next;
- timer->next = timer->prev = NULL;
- restore_flags(flags);
- timer->expires -= jiffies;
- return 1;
- }
- restore_flags(flags);
- return 0;
-#endif
-}
-
-unsigned long timer_active = 0;
-struct timer_struct timer_table[32];
-
-/*
- * Hmm.. Changed this, as the GNU make sources (load.c) seems to
- * imply that avenrun[] is the standard name for this kind of thing.
- * Nothing else seems to be standardized: the fractional size etc
- * all seem to differ on different machines.
- */
-unsigned long avenrun[3] = { 0,0,0 };
-
-/*
- * Nr of active tasks - counted in fixed-point numbers
- */
-static unsigned long count_active_tasks(void)
-{
- struct task_struct **p;
- unsigned long nr = 0;
-
- for(p = &LAST_TASK; p > &FIRST_TASK; --p)
- if (*p && ((*p)->state == TASK_RUNNING ||
- (*p)->state == TASK_UNINTERRUPTIBLE ||
- (*p)->state == TASK_SWAPPING))
- nr += FIXED_1;
- return nr;
-}
-
-static inline void calc_load(void)
-{
- unsigned long active_tasks; /* fixed-point */
- static int count = LOAD_FREQ;
-
- if (count-- > 0)
- return;
- count = LOAD_FREQ;
- active_tasks = count_active_tasks();
- CALC_LOAD(avenrun[0], EXP_1, active_tasks);
- CALC_LOAD(avenrun[1], EXP_5, active_tasks);
- CALC_LOAD(avenrun[2], EXP_15, active_tasks);
-}
-
-/*
- * this routine handles the overflow of the microsecond field
- *
- * The tricky bits of code to handle the accurate clock support
- * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame.
- * They were originally developed for SUN and DEC kernels.
- * All the kudos should go to Dave for this stuff.
- *
- * These were ported to Linux by Philip Gladstone.
- */
-static void second_overflow(void)
-{
- long ltemp;
- /* last time the cmos clock got updated */
- static long last_rtc_update=0;
- extern int set_rtc_mmss(unsigned long);
-
- /* Bump the maxerror field */
- time_maxerror = (0x70000000-time_maxerror < time_tolerance) ?
- 0x70000000 : (time_maxerror + time_tolerance);
-
- /* Run the PLL */
- if (time_offset < 0) {
- ltemp = (-(time_offset+1) >> (SHIFT_KG + time_constant)) + 1;
- time_adj = ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
- time_offset += (time_adj * HZ) >> (SHIFT_SCALE - SHIFT_UPDATE);
- time_adj = - time_adj;
- } else if (time_offset > 0) {
- ltemp = ((time_offset-1) >> (SHIFT_KG + time_constant)) + 1;
- time_adj = ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
- time_offset -= (time_adj * HZ) >> (SHIFT_SCALE - SHIFT_UPDATE);
- } else {
- time_adj = 0;
- }
-
- time_adj += (time_freq >> (SHIFT_KF + SHIFT_HZ - SHIFT_SCALE))
- + FINETUNE;
-
- /* Handle the leap second stuff */
- switch (time_status) {
- case TIME_INS:
- /* ugly divide should be replaced */
- if (xtime.tv_sec % 86400 == 0) {
- xtime.tv_sec--; /* !! */
- time_status = TIME_OOP;
- printk("Clock: inserting leap second 23:59:60 GMT\n");
- }
- break;
-
- case TIME_DEL:
- /* ugly divide should be replaced */
- if (xtime.tv_sec % 86400 == 86399) {
- xtime.tv_sec++;
- time_status = TIME_OK;
- printk("Clock: deleting leap second 23:59:59 GMT\n");
- }
- break;
-
- case TIME_OOP:
- time_status = TIME_OK;
- break;
- }
- if (xtime.tv_sec > last_rtc_update + 660)
- if (set_rtc_mmss(xtime.tv_sec) == 0)
- last_rtc_update = xtime.tv_sec;
- else
- last_rtc_update = xtime.tv_sec - 600; /* do it again in one min */
-}
-
-/*
- * disregard lost ticks for now.. We don't care enough.
- */
-static void timer_bh(void * unused)
-{
- unsigned long mask;
- struct timer_struct *tp;
- struct timer_list * timer;
-
- cli();
- while ((timer = timer_head.next) != &timer_head && timer->expires < jiffies) {
- void (*fn)(unsigned long) = timer->function;
- unsigned long data = timer->data;
- timer->next->prev = timer->prev;
- timer->prev->next = timer->next;
- timer->next = timer->prev = NULL;
- sti();
- fn(data);
- cli();
- }
- sti();
-
- for (mask = 1, tp = timer_table+0 ; mask ; tp++,mask += mask) {
- if (mask > timer_active)
- break;
- if (!(mask & timer_active))
- continue;
- if (tp->expires > jiffies)
- continue;
- timer_active &= ~mask;
- tp->fn();
- sti();
- }
-}
-
-void tqueue_bh(void * unused)
-{
- run_task_queue(&tq_timer);
-}
-
-void immediate_bh(void * unused)
-{
- run_task_queue(&tq_immediate);
-}
-
-/*
- * The int argument is really a (struct pt_regs *), in case the
- * interrupt wants to know from where it was called. The timer
- * irq uses this to decide if it should update the user or system
- * times.
- */
-static void do_timer(struct pt_regs * regs)
-{
- unsigned long mask;
- struct timer_struct *tp;
-
- long ltemp, psecs;
-
- /* Advance the phase, once it gets to one microsecond, then
- * advance the tick more.
- */
- time_phase += time_adj;
- if (time_phase < -FINEUSEC) {
- ltemp = -time_phase >> SHIFT_SCALE;
- time_phase += ltemp << SHIFT_SCALE;
- xtime.tv_usec += tick + time_adjust_step - ltemp;
- }
- else if (time_phase > FINEUSEC) {
- ltemp = time_phase >> SHIFT_SCALE;
- time_phase -= ltemp << SHIFT_SCALE;
- xtime.tv_usec += tick + time_adjust_step + ltemp;
- } else
- xtime.tv_usec += tick + time_adjust_step;
-
- if (time_adjust)
- {
- /* We are doing an adjtime thing.
- *
- * Modify the value of the tick for next time.
- * Note that a positive delta means we want the clock
- * to run fast. This means that the tick should be bigger
- *
- * Limit the amount of the step for *next* tick to be
- * in the range -tickadj .. +tickadj
- */
- if (time_adjust > tickadj)
- time_adjust_step = tickadj;
- else if (time_adjust < -tickadj)
- time_adjust_step = -tickadj;
- else
- time_adjust_step = time_adjust;
-
- /* Reduce by this step the amount of time left */
- time_adjust -= time_adjust_step;
- }
- else
- time_adjust_step = 0;
-
- if (xtime.tv_usec >= 1000000) {
- xtime.tv_usec -= 1000000;
- xtime.tv_sec++;
- second_overflow();
- }
-
- jiffies++;
- calc_load();
- if (USES_USER_TIME(regs)) {
- current->utime++;
- if (current != task[0]) {
- if (current->priority < 15)
- kstat.cpu_nice++;
- else
- kstat.cpu_user++;
- }
- /* Update ITIMER_VIRT for current task if not in a system call */
- if (current->it_virt_value && !(--current->it_virt_value)) {
- current->it_virt_value = current->it_virt_incr;
- send_sig(SIGVTALRM,current,1);
- }
- } else {
- current->stime++;
- if(current != task[0])
- kstat.cpu_system++;
-#if defined (CONFIG_PROFILE) & !defined (__mips__)
- if (prof_buffer && current != task[0]) {
- unsigned long eip = regs->eip;
- eip >>= 2;
- if (eip < prof_len)
- prof_buffer[eip]++;
- }
-#endif
- }
- /*
- * check the cpu time limit on the process.
- */
- if ((current->rlim[RLIMIT_CPU].rlim_max != RLIM_INFINITY) &&
- (((current->stime + current->utime) / HZ) >= current->rlim[RLIMIT_CPU].rlim_max))
- send_sig(SIGKILL, current, 1);
- if ((current->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) &&
- (((current->stime + current->utime) % HZ) == 0)) {
- psecs = (current->stime + current->utime) / HZ;
- /* send when equal */
- if (psecs == current->rlim[RLIMIT_CPU].rlim_cur)
- send_sig(SIGXCPU, current, 1);
- /* and every five seconds thereafter. */
- else if ((psecs > current->rlim[RLIMIT_CPU].rlim_cur) &&
- ((psecs - current->rlim[RLIMIT_CPU].rlim_cur) % 5) == 0)
- send_sig(SIGXCPU, current, 1);
- }
-
- if (current != task[0] && 0 > --current->counter) {
- current->counter = 0;
- need_resched = 1;
- }
- /* Update ITIMER_PROF for the current task */
- if (current->it_prof_value && !(--current->it_prof_value)) {
- current->it_prof_value = current->it_prof_incr;
- send_sig(SIGPROF,current,1);
- }
- for (mask = 1, tp = timer_table+0 ; mask ; tp++,mask += mask) {
- if (mask > timer_active)
- break;
- if (!(mask & timer_active))
- continue;
- if (tp->expires > jiffies)
- continue;
- mark_bh(TIMER_BH);
- }
- cli();
- itimer_ticks++;
- if (itimer_ticks > itimer_next)
- need_resched = 1;
- if (timer_head.next->expires < jiffies)
- mark_bh(TIMER_BH);
- if (tq_timer != &tq_last)
- mark_bh(TQUEUE_BH);
- sti();
-}
-
-asmlinkage int sys_alarm(long seconds)
-{
- struct itimerval it_new, it_old;
-
- 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;
- _setitimer(ITIMER_REAL, &it_new, &it_old);
- return(it_old.it_value.tv_sec + (it_old.it_value.tv_usec / 1000000));
-}
-
-asmlinkage int sys_getpid(void)
-{
- return current->pid;
-}
-
-asmlinkage int sys_getppid(void)
-{
- return current->p_opptr->pid;
-}
-
-asmlinkage int sys_getuid(void)
-{
- return current->uid;
-}
-
-asmlinkage int sys_geteuid(void)
-{
- return current->euid;
-}
-
-asmlinkage int sys_getgid(void)
-{
- return current->gid;
-}
-
-asmlinkage int sys_getegid(void)
-{
- return current->egid;
-}
-
-asmlinkage int sys_nice(long increment)
-{
- int newprio;
-
- if (increment < 0 && !suser())
- return -EPERM;
- newprio = current->priority - increment;
- if (newprio < 1)
- newprio = 1;
- if (newprio > 35)
- newprio = 35;
- current->priority = newprio;
- return 0;
-}
-
-static void show_task(int nr,struct task_struct * p)
-{
- unsigned long free;
- static char * stat_nam[] = { "R", "S", "D", "Z", "T", "W" };
-
- printk("%-8s %3d ", p->comm, (p == current) ? -nr : nr);
- if (((unsigned) p->state) < sizeof(stat_nam)/sizeof(char *))
- printk(stat_nam[p->state]);
- else
- printk(" ");
- if (p == current)
- printk(" current ");
- else
- printk(" %08lX ", (unsigned long *)p->tss.cp0_epc);
- for (free = 1; free < 1024 ; free++) {
- if (((unsigned long *)p->kernel_stack_page)[free])
- break;
- }
- printk("%5lu %5d %6d ", free << 2, p->pid, p->p_pptr->pid);
- if (p->p_cptr)
- printk("%5d ", p->p_cptr->pid);
- else
- printk(" ");
- if (p->p_ysptr)
- printk("%7d", p->p_ysptr->pid);
- else
- printk(" ");
- if (p->p_osptr)
- printk(" %5d\n", p->p_osptr->pid);
- else
- printk("\n");
-}
-
-void show_state(void)
-{
- int i;
-
- printk(" free sibling\n");
- printk(" task PC stack pid father child younger older\n");
- for (i=0 ; i<NR_TASKS ; i++)
- if (task[i])
- show_task(i,task[i]);
-}
-
-void sched_init(void)
-{
- bh_base[TIMER_BH].routine = timer_bh;
- bh_base[TQUEUE_BH].routine = tqueue_bh;
- bh_base[IMMEDIATE_BH].routine = immediate_bh;
- if (sizeof(struct sigaction) != 16)
- panic("Struct sigaction MUST be 16 bytes");
-
- outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
- outb_p(LATCH & 0xff , 0x40); /* LSB */
- outb(LATCH >> 8 , 0x40); /* MSB */
- if (request_irq(TIMER_IRQ,(void (*)(int)) do_timer, 0, "timer") != 0)
- panic("Could not allocate timer IRQ!");
-}
diff --git a/arch/mips/splx.c b/arch/mips/splx.c
deleted file mode 100644
index 5ff5e8284..000000000
--- a/arch/mips/splx.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * splx.c - SYSV DDI/DKI ipl manipulation functions
- *
- * Internally, many unices use a range of different interrupt
- * privilege levels, ie from "allow all interrupts" (7) to
- * "allow no interrupts." (0) under SYSV.
- *
- * This a simple splx() function behaves as the SYSV DDI/DKI function does,
- * although since Linux only implements the equivalent of level 0 (cli) and
- * level 7 (sti), this implementation only implements those levels.
- *
- * Also, unlike the current Linux routines, splx() also returns the
- * old privilege level so that it can be restored.
- */
-
-#include <asm/system.h>
-#include <asm/mipsregs.h>
-
-int splx (int new_level)
-{
- register int old_level, tmp;
-
- save_flags(tmp);
- old_level = ((tmp & (ST0_IE|ST0_ERL|ST0_EXL)) == ST0_IE) ? 7 : 0;
- if (new_level)
- sti();
- else
- cli();
- return old_level;
-}
diff --git a/arch/mips/traps.c b/arch/mips/traps.c
deleted file mode 100644
index 9cb1252d5..000000000
--- a/arch/mips/traps.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * linux/kernel/traps.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- */
-
-/*
- * 'traps.c' handles hardware traps and faults after we have saved some
- * state in 'asm.s'. Currently mostly a debugging-aid, will be extended
- * to mainly kill the offending process (probably by giving it a signal,
- * but possibly by killing it outright if necessary).
- */
-#include <linux/head.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ptrace.h>
-
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/mipsregs.h>
-
-static inline void console_verbose(void)
-{
- extern int console_loglevel;
- console_loglevel = 15;
-}
-
-asmlinkage extern void handle_int(void);
-asmlinkage extern void handle_mod(void);
-asmlinkage extern void handle_tlbl(void);
-asmlinkage extern void handle_tlbs(void);
-asmlinkage extern void handle_adel(void);
-asmlinkage extern void handle_ades(void);
-asmlinkage extern void handle_ibe(void);
-asmlinkage extern void handle_dbe(void);
-asmlinkage extern void handle_sys(void);
-asmlinkage extern void handle_bp(void);
-asmlinkage extern void handle_ri(void);
-asmlinkage extern void handle_cpu(void);
-asmlinkage extern void handle_ov(void);
-asmlinkage extern void handle_tr(void);
-asmlinkage extern void handle_reserved(void);
-asmlinkage extern void handle_fpe(void);
-
-void die_if_kernel(char * str, struct pt_regs * regs, long err)
-{
- int i;
- unsigned long *sp, *pc;
-
- if (regs->cp0_status & (ST0_ERL|ST0_EXL) == 0)
- return;
-
- sp = (unsigned long *)regs->reg29;
- pc = (unsigned long *)regs->cp0_epc;
-
- console_verbose();
- printk("%s: %08lx\n", str, err );
-
- /*
- * Saved main processor registers
- */
- printk("at : %08lx\n", regs->reg1);
- printk("v0 : %08lx %08lx\n", regs->reg2, regs->reg3);
- printk("a0 : %08lx %08lx %08lx %08lx\n",
- regs->reg4, regs->reg5, regs->reg6, regs->reg7);
- printk("t0 : %08lx %08lx %08lx %08lx %08lx\n",
- regs->reg8, regs->reg9, regs->reg10, regs->reg11, regs->reg12);
- printk("t5 : %08lx %08lx %08lx %08lx %08lx\n",
- regs->reg13, regs->reg14, regs->reg15, regs->reg24, regs->reg25);
- printk("s0 : %08lx %08lx %08lx %08lx\n",
- regs->reg16, regs->reg17, regs->reg18, regs->reg19);
- printk("s4 : %08lx %08lx %08lx %08lx\n",
- regs->reg20, regs->reg21, regs->reg22, regs->reg23);
- printk("gp : %08lx\n", regs->reg28);
- printk("sp : %08lx\n", regs->reg29);
- printk("fp/s8: %08lx\n", regs->reg30);
- printk("ra : %08lx\n", regs->reg31);
-
- /*
- * Saved cp0 registers
- */
- printk("EPC : %08lx\nErrorEPC: %08lx\nStatus: %08lx\n",
- regs->cp0_epc, regs->cp0_errorepc, regs->cp0_status);
- /*
- * Some goodies...
- */
- printk("Int : %ld\n", regs->interrupt);
-
- /*
- * Dump the stack
- */
- if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page)
- printk("Corrupted stack page\n");
- printk("Process %s (pid: %d, process nr: %d, stackpage=%08lx)\nStack: ",
- current->comm, current->pid, 0xffff & i,
- current->kernel_stack_page);
- for(i=0;i<5;i++)
- printk("%08lx ", *sp++);
-
- printk("\nCode: ");
- for(i=0;i<5;i++)
- printk("%08lx ", *pc++);
- printk("\n");
- do_exit(SIGSEGV);
-}
-
-void trap_init(void)
-{
- int i;
-
-#if 0
- set_except_vector(0, handle_int);
- set_except_vector(1, handle_mod);
- 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(14, handle_reserved);
- set_except_vector(15, handle_fpe);
-
- for (i=16;i<256;i++)
- set_except_vector(i, handle_reserved);
-#endif
-}