Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/arch/cris/arch-v10/kernel/Makefile b/arch/cris/arch-v10/kernel/Makefile
new file mode 100644
index 0000000..5276160
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/Makefile
@@ -0,0 +1,17 @@
+# $Id: Makefile,v 1.5 2004/06/02 08:24:38 starvik Exp $
+#
+# Makefile for the linux kernel.
+#
+
+extra-y	:= head.o
+
+
+obj-y   := entry.o traps.o shadows.o debugport.o irq.o \
+	   process.o setup.o signal.o traps.o time.o ptrace.o
+
+obj-$(CONFIG_ETRAX_KGDB) += kgdb.o
+obj-$(CONFIG_ETRAX_FAST_TIMER) += fasttimer.o
+obj-$(CONFIG_MODULES)    += crisksyms.o
+
+clean:
+
diff --git a/arch/cris/arch-v10/kernel/asm-offsets.c b/arch/cris/arch-v10/kernel/asm-offsets.c
new file mode 100644
index 0000000..1aa3cc4
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/asm-offsets.c
@@ -0,0 +1,47 @@
+#include <linux/sched.h>
+#include <asm/thread_info.h>
+
+/*
+ * Generate definitions needed by assembly language modules.
+ * This code generates raw asm output which is post-processed to extract
+ * and format the required data.
+ */
+
+#define DEFINE(sym, val) \
+        asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define BLANK() asm volatile("\n->" : : )
+
+int main(void)
+{
+#define ENTRY(entry) DEFINE(PT_ ## entry, offsetof(struct pt_regs, entry))
+	ENTRY(orig_r10);
+	ENTRY(r13); 
+	ENTRY(r12); 
+	ENTRY(r11);
+        ENTRY(r10);
+        ENTRY(r9);
+        ENTRY(mof);
+        ENTRY(dccr);
+        ENTRY(srp);
+	BLANK();
+#undef ENTRY
+#define ENTRY(entry) DEFINE(TI_ ## entry, offsetof(struct thread_info, entry))
+        ENTRY(task);
+        ENTRY(flags);
+        ENTRY(preempt_count);
+        BLANK();
+#undef ENTRY
+#define ENTRY(entry) DEFINE(THREAD_ ## entry, offsetof(struct thread_struct, entry))
+	ENTRY(ksp);
+        ENTRY(usp);
+        ENTRY(dccr);
+        BLANK();
+#undef ENTRY
+#define ENTRY(entry) DEFINE(TASK_ ## entry, offsetof(struct task_struct, entry))
+        ENTRY(pid);
+        BLANK();
+        DEFINE(LCLONE_VM, CLONE_VM);
+        DEFINE(LCLONE_UNTRACED, CLONE_UNTRACED);
+        return 0;
+}
diff --git a/arch/cris/arch-v10/kernel/crisksyms.c b/arch/cris/arch-v10/kernel/crisksyms.c
new file mode 100644
index 0000000..b332bf9
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/crisksyms.c
@@ -0,0 +1,17 @@
+#include <linux/config.h>
+#include <linux/module.h>
+#include <asm/io.h>
+#include <asm/arch/svinto.h>
+
+/* Export shadow registers for the CPU I/O pins */
+EXPORT_SYMBOL(genconfig_shadow);
+EXPORT_SYMBOL(port_pa_data_shadow);
+EXPORT_SYMBOL(port_pa_dir_shadow);
+EXPORT_SYMBOL(port_pb_data_shadow);
+EXPORT_SYMBOL(port_pb_dir_shadow);
+EXPORT_SYMBOL(port_pb_config_shadow);
+EXPORT_SYMBOL(port_g_data_shadow);
+
+/* Cache flush functions */
+EXPORT_SYMBOL(flush_etrax_cache);
+EXPORT_SYMBOL(prepare_rx_descriptor);
diff --git a/arch/cris/arch-v10/kernel/debugport.c b/arch/cris/arch-v10/kernel/debugport.c
new file mode 100644
index 0000000..6cf069e
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/debugport.c
@@ -0,0 +1,531 @@
+/* Serialport functions for debugging
+ *
+ * Copyright (c) 2000 Axis Communications AB
+ *
+ * Authors:  Bjorn Wesen
+ *
+ * Exports:
+ *    console_print_etrax(char *buf)
+ *    int getDebugChar()
+ *    putDebugChar(int)
+ *    enableDebugIRQ()
+ *    init_etrax_debug()
+ *
+ * $Log: debugport.c,v $
+ * Revision 1.19  2004/10/21 07:26:16  starvik
+ * Made it possible to specify console settings on kernel command line.
+ *
+ * Revision 1.18  2004/10/19 13:07:37  starvik
+ * Merge of Linux 2.6.9
+ *
+ * Revision 1.17  2004/09/29 10:33:46  starvik
+ * Resolved a dealock when printing debug from kernel.
+ *
+ * Revision 1.16  2004/08/24 06:12:19  starvik
+ * Whitespace cleanup
+ *
+ * Revision 1.15  2004/08/16 12:37:19  starvik
+ * Merge of Linux 2.6.8
+ *
+ * Revision 1.14  2004/05/17 13:11:29  starvik
+ * Disable DMA until real serial driver is up
+ *
+ * Revision 1.13  2004/05/14 07:58:01  starvik
+ * Merge of changes from 2.4
+ *
+ * Revision 1.12  2003/09/11 07:29:49  starvik
+ * Merge of Linux 2.6.0-test5
+ *
+ * Revision 1.11  2003/07/07 09:53:36  starvik
+ * Revert all the 2.5.74 merge changes to make the console work again
+ *
+ * Revision 1.9  2003/02/17 17:07:23  starvik
+ * Solved the problem with corrupted debug output (from Linux 2.4)
+ *   * Wait until DMA, FIFO and pipe is empty before and after transmissions
+ *   * Buffer data until a FIFO flush can be triggered.
+ *
+ * Revision 1.8  2003/01/22 06:48:36  starvik
+ * Fixed warnings issued by GCC 3.2.1
+ *
+ * Revision 1.7  2002/12/12 08:26:32  starvik
+ * Don't use C-comments inside CVS comments
+ *
+ * Revision 1.6  2002/12/11 15:42:02  starvik
+ * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/
+ *
+ * Revision 1.5  2002/11/20 06:58:03  starvik
+ * Compiles with kgdb
+ *
+ * Revision 1.4  2002/11/19 14:35:24  starvik
+ * Changes from linux 2.4
+ * Changed struct initializer syntax to the currently prefered notation
+ *
+ * Revision 1.3  2002/11/06 09:47:03  starvik
+ * Modified for new interrupt macros
+ *
+ * Revision 1.2  2002/01/21 15:21:50  bjornw
+ * Update for kdev_t changes
+ *
+ * Revision 1.6  2001/04/17 13:58:39  orjanf
+ * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB.
+ *
+ * Revision 1.5  2001/03/26 14:22:05  bjornw
+ * Namechange of some config options
+ *
+ * Revision 1.4  2000/10/06 12:37:26  bjornw
+ * Use physical addresses when talking to DMA
+ *
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/major.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <asm/system.h>
+#include <asm/arch/svinto.h>
+#include <asm/io.h>             /* Get SIMCOUT. */
+
+struct dbg_port
+{
+  unsigned int index;
+  const volatile unsigned* read;
+  volatile char* write;
+  volatile unsigned* xoff;
+  volatile char* baud;
+  volatile char* tr_ctrl;
+  volatile char* rec_ctrl;
+  unsigned long irq;
+  unsigned int started;
+  unsigned long baudrate;
+  unsigned char parity;
+  unsigned int bits;
+};
+
+struct dbg_port ports[]=
+{
+  {
+    0,
+    R_SERIAL0_READ,
+    R_SERIAL0_TR_DATA,
+    R_SERIAL0_XOFF,
+    R_SERIAL0_BAUD,
+    R_SERIAL0_TR_CTRL,
+    R_SERIAL0_REC_CTRL,
+    IO_STATE(R_IRQ_MASK1_SET, ser0_data, set)
+  },
+  {
+    1,
+    R_SERIAL1_READ,
+    R_SERIAL1_TR_DATA,
+    R_SERIAL1_XOFF,
+    R_SERIAL1_BAUD,
+    R_SERIAL1_TR_CTRL,
+    R_SERIAL1_REC_CTRL,
+    IO_STATE(R_IRQ_MASK1_SET, ser1_data, set)
+  },
+  {
+    2,
+    R_SERIAL2_READ,
+    R_SERIAL2_TR_DATA,
+    R_SERIAL2_XOFF,
+    R_SERIAL2_BAUD,
+    R_SERIAL2_TR_CTRL,
+    R_SERIAL2_REC_CTRL,
+    IO_STATE(R_IRQ_MASK1_SET, ser2_data, set)
+  },
+  {
+    3,
+    R_SERIAL3_READ,
+    R_SERIAL3_TR_DATA,
+    R_SERIAL3_XOFF,
+    R_SERIAL3_BAUD,
+    R_SERIAL3_TR_CTRL,
+    R_SERIAL3_REC_CTRL,
+    IO_STATE(R_IRQ_MASK1_SET, ser3_data, set)
+  }
+};
+
+static struct tty_driver *serial_driver;
+
+struct dbg_port* port =
+#if defined(CONFIG_ETRAX_DEBUG_PORT0)
+  &ports[0];
+#elif defined(CONFIG_ETRAX_DEBUG_PORT1)
+  &ports[1];
+#elif defined(CONFIG_ETRAX_DEBUG_PORT2)
+  &ports[2];
+#elif defined(CONFIG_ETRAX_DEBUG_PORT3)
+  &ports[3];
+#else
+  NULL;
+#endif
+/* Used by serial.c to register a debug_write_function so that the normal
+ * serial driver is used for kernel debug output
+ */
+typedef int (*debugport_write_function)(int i, const char *buf, unsigned int len);
+
+debugport_write_function debug_write_function = NULL;
+
+static void
+start_port(void)
+{
+	unsigned long rec_ctrl = 0;
+	unsigned long tr_ctrl = 0;
+
+	if (!port)
+		return;
+
+	if (port->started)
+		return;
+	port->started = 1;
+
+	if (port->index == 0)
+	{
+		genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6);
+		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused);
+	}
+	else if (port->index == 1)
+	{
+		genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8);
+		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb);
+	}
+	else if (port->index == 2)
+	{
+		genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2);
+		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0);
+		genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma3);
+		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, par0);
+		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, ser2, select);
+	}
+	else
+	{
+		genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma4);
+		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, par1);
+		genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma5);
+		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, par1);
+		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, ser3, select);
+	}
+
+	*R_GEN_CONFIG = genconfig_shadow;
+
+	*port->xoff =
+		IO_STATE(R_SERIAL0_XOFF, tx_stop, enable) |
+		IO_STATE(R_SERIAL0_XOFF, auto_xoff, disable) |
+		IO_FIELD(R_SERIAL0_XOFF, xoff_char, 0);
+
+	switch (port->baudrate)
+	{
+	case 0:
+	case 115200:
+		*port->baud =
+		  IO_STATE(R_SERIAL0_BAUD, tr_baud, c115k2Hz) |
+		  IO_STATE(R_SERIAL0_BAUD, rec_baud, c115k2Hz);
+		break;
+	case 1200:
+		*port->baud =
+		  IO_STATE(R_SERIAL0_BAUD, tr_baud, c1200Hz) |
+		  IO_STATE(R_SERIAL0_BAUD, rec_baud, c1200Hz);
+		break;
+	case 2400:
+		*port->baud =
+		  IO_STATE(R_SERIAL0_BAUD, tr_baud, c2400Hz) |
+		  IO_STATE(R_SERIAL0_BAUD, rec_baud, c2400Hz);
+		break;
+	case 4800:
+		*port->baud =
+		  IO_STATE(R_SERIAL0_BAUD, tr_baud, c4800Hz) |
+		  IO_STATE(R_SERIAL0_BAUD, rec_baud, c4800Hz);
+		break;
+	case 9600:
+		*port->baud =
+		  IO_STATE(R_SERIAL0_BAUD, tr_baud, c9600Hz) |
+		  IO_STATE(R_SERIAL0_BAUD, rec_baud, c9600Hz);
+		  break;
+	case 19200:
+		*port->baud =
+		  IO_STATE(R_SERIAL0_BAUD, tr_baud, c19k2Hz) |
+		  IO_STATE(R_SERIAL0_BAUD, rec_baud, c19k2Hz);
+		 break;
+	case 38400:
+		*port->baud =
+		  IO_STATE(R_SERIAL0_BAUD, tr_baud, c38k4Hz) |
+		  IO_STATE(R_SERIAL0_BAUD, rec_baud, c38k4Hz);
+		break;
+	case 57600:
+		*port->baud =
+		  IO_STATE(R_SERIAL0_BAUD, tr_baud, c57k6Hz) |
+		  IO_STATE(R_SERIAL0_BAUD, rec_baud, c57k6Hz);
+		break;
+	default:
+		*port->baud =
+		  IO_STATE(R_SERIAL0_BAUD, tr_baud, c115k2Hz) |
+		  IO_STATE(R_SERIAL0_BAUD, rec_baud, c115k2Hz);
+		  break;
+        }
+
+	if (port->parity == 'E') {
+		rec_ctrl =
+		  IO_STATE(R_SERIAL0_REC_CTRL, rec_par, even) |
+		  IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable);
+		tr_ctrl =
+		  IO_STATE(R_SERIAL0_TR_CTRL, tr_par, even) |
+		  IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable);
+	} else if (port->parity == 'O') {
+		rec_ctrl =
+		  IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd) |
+		  IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable);
+		tr_ctrl =
+		  IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd) |
+		  IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable);
+	} else {
+		rec_ctrl =
+		  IO_STATE(R_SERIAL0_REC_CTRL, rec_par, even) |
+		  IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, disable);
+		tr_ctrl =
+		  IO_STATE(R_SERIAL0_TR_CTRL, tr_par, even) |
+		  IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, disable);
+	}
+
+	if (port->bits == 7)
+	{
+		rec_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_7bit);
+		tr_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_7bit);
+	}
+	else
+	{
+		rec_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_8bit);
+		tr_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_8bit);
+	}
+
+	*port->rec_ctrl =
+		IO_STATE(R_SERIAL0_REC_CTRL, dma_err, stop) |
+		IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable) |
+		IO_STATE(R_SERIAL0_REC_CTRL, rts_, active) |
+		IO_STATE(R_SERIAL0_REC_CTRL, sampling, middle) |
+		IO_STATE(R_SERIAL0_REC_CTRL, rec_stick_par, normal) |
+		rec_ctrl;
+
+	*port->tr_ctrl =
+		IO_FIELD(R_SERIAL0_TR_CTRL, txd, 0) |
+		IO_STATE(R_SERIAL0_TR_CTRL, tr_enable, enable) |
+		IO_STATE(R_SERIAL0_TR_CTRL, auto_cts, disabled) |
+		IO_STATE(R_SERIAL0_TR_CTRL, stop_bits, one_bit) |
+		IO_STATE(R_SERIAL0_TR_CTRL, tr_stick_par, normal) |
+		tr_ctrl;
+}
+
+static void
+console_write_direct(struct console *co, const char *buf, unsigned int len)
+{
+	int i;
+	unsigned long flags;
+	local_irq_save(flags);
+	/* Send data */
+	for (i = 0; i < len; i++) {
+		/* Wait until transmitter is ready and send.*/
+		while (!(*port->read & IO_MASK(R_SERIAL0_READ, tr_ready)))
+			;
+		*port->write = buf[i];
+	}
+	local_irq_restore(flags);
+}
+
+static void
+console_write(struct console *co, const char *buf, unsigned int len)
+{
+	if (!port)
+		return;
+
+#ifdef CONFIG_SVINTO_SIM
+	/* no use to simulate the serial debug output */
+	SIMCOUT(buf, len);
+	return;
+#endif
+
+	start_port();
+
+#ifdef CONFIG_ETRAX_KGDB
+	/* kgdb needs to output debug info using the gdb protocol */
+	putDebugString(buf, len);
+	return;
+#endif
+
+	if (debug_write_function)
+		debug_write_function(co->index, buf, len);
+	else
+		console_write_direct(co, buf, len);
+}
+
+/* legacy function */
+
+void
+console_print_etrax(const char *buf)
+{
+	console_write(NULL, buf, strlen(buf));
+}
+
+/* Use polling to get a single character FROM the debug port */
+
+int
+getDebugChar(void)
+{
+	unsigned long readval;
+
+	do {
+		readval = *port->read;
+	} while (!(readval & IO_MASK(R_SERIAL0_READ, data_avail)));
+
+	return (readval & IO_MASK(R_SERIAL0_READ, data_in));
+}
+
+/* Use polling to put a single character to the debug port */
+
+void
+putDebugChar(int val)
+{
+	while (!(*port->read & IO_MASK(R_SERIAL0_READ, tr_ready)))
+		;
+	*port->write = val;
+}
+
+/* Enable irq for receiving chars on the debug port, used by kgdb */
+
+void
+enableDebugIRQ(void)
+{
+	*R_IRQ_MASK1_SET = port->irq;
+	/* use R_VECT_MASK directly, since we really bypass Linux normal
+	 * IRQ handling in kgdb anyway, we don't need to use enable_irq
+	 */
+	*R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set);
+
+	*port->rec_ctrl = IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable);
+}
+
+static struct tty_driver*
+etrax_console_device(struct console* co, int *index)
+{
+	return serial_driver;
+}
+
+static int __init
+console_setup(struct console *co, char *options)
+{
+	char* s;
+
+	if (options) {
+		port = &ports[co->index];
+		port->baudrate = 115200;
+                port->parity = 'N';
+                port->bits = 8;
+		port->baudrate = simple_strtoul(options, NULL, 10);
+		s = options;
+		while(*s >= '0' && *s <= '9')
+			s++;
+		if (*s) port->parity = *s++;
+		if (*s) port->bits   = *s++ - '0';
+		port->started = 0;
+		start_port();
+	}
+	return 0;
+}
+
+static struct console sercons = {
+	name : "ttyS",
+	write: console_write,
+	read : NULL,
+	device : etrax_console_device,
+	unblank : NULL,
+	setup : console_setup,
+	flags : CON_PRINTBUFFER,
+	index : -1,
+	cflag : 0,
+	next : NULL
+};
+static struct console sercons0 = {
+	name : "ttyS",
+	write: console_write,
+	read : NULL,
+	device : etrax_console_device,
+	unblank : NULL,
+	setup : console_setup,
+	flags : CON_PRINTBUFFER,
+	index : 0,
+	cflag : 0,
+	next : NULL
+};
+
+static struct console sercons1 = {
+	name : "ttyS",
+	write: console_write,
+	read : NULL,
+	device : etrax_console_device,
+	unblank : NULL,
+	setup : console_setup,
+	flags : CON_PRINTBUFFER,
+	index : 1,
+	cflag : 0,
+	next : NULL
+};
+static struct console sercons2 = {
+	name : "ttyS",
+	write: console_write,
+	read : NULL,
+	device : etrax_console_device,
+	unblank : NULL,
+	setup : console_setup,
+	flags : CON_PRINTBUFFER,
+	index : 2,
+	cflag : 0,
+	next : NULL
+};
+static struct console sercons3 = {
+	name : "ttyS",
+	write: console_write,
+	read : NULL,
+	device : etrax_console_device,
+	unblank : NULL,
+	setup : console_setup,
+	flags : CON_PRINTBUFFER,
+	index : 3,
+	cflag : 0,
+	next : NULL
+};
+/*
+ *      Register console (for printk's etc)
+ */
+
+int __init
+init_etrax_debug(void)
+{
+	static int first = 1;
+
+	if (!first) {
+		if (!port) {
+			register_console(&sercons0);
+			register_console(&sercons1);
+			register_console(&sercons2);
+			register_console(&sercons3);
+			unregister_console(&sercons);
+		}
+		return 0;
+	}
+	first = 0;
+	if (port)
+		register_console(&sercons);
+	return 0;
+}
+
+int __init
+init_console(void)
+{
+	serial_driver = alloc_tty_driver(1);
+	if (!serial_driver)
+		return -ENOMEM;
+	return 0;
+}
+
+__initcall(init_etrax_debug);
diff --git a/arch/cris/arch-v10/kernel/entry.S b/arch/cris/arch-v10/kernel/entry.S
new file mode 100644
index 0000000..1bc44f4
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/entry.S
@@ -0,0 +1,1132 @@
+/* $Id: entry.S,v 1.23 2004/10/19 13:07:37 starvik Exp $
+ *
+ *  linux/arch/cris/entry.S
+ *
+ *  Copyright (C) 2000, 2001, 2002 Axis Communications AB
+ *
+ *  Authors:	Bjorn Wesen (bjornw@axis.com)
+ *
+ *  $Log: entry.S,v $
+ *  Revision 1.23  2004/10/19 13:07:37  starvik
+ *  Merge of Linux 2.6.9
+ *
+ *  Revision 1.22  2004/06/21 10:29:55  starvik
+ *  Merge of Linux 2.6.7
+ *
+ *  Revision 1.21  2004/06/09 05:30:27  starvik
+ *  Clean up multiple interrupt handling.
+ *    Prevent interrupts from interrupting each other.
+ *    Handle all active interrupts.
+ *
+ *  Revision 1.20  2004/06/08 08:55:32  starvik
+ *  Removed unused code
+ *
+ *  Revision 1.19  2004/06/04 11:56:15  starvik
+ *  Implemented page table lookup for refills in assembler for improved performance.
+ *
+ *  Revision 1.18  2004/05/11 12:28:25  starvik
+ *  Merge of Linux 2.6.6
+ *
+ *  Revision 1.17  2003/09/11 07:29:49  starvik
+ *  Merge of Linux 2.6.0-test5
+ *
+ *  Revision 1.16  2003/07/04 08:27:41  starvik
+ *  Merge of Linux 2.5.74
+ *
+ *  Revision 1.15  2003/04/09 07:32:55  starvik
+ *  resume should return task_struct, not thread_info
+ *
+ *  Revision 1.14  2003/04/09 05:20:44  starvik
+ *  Merge of Linux 2.5.67
+ *
+ *  Revision 1.13  2002/12/11 15:42:02  starvik
+ *  Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/*.c
+ *
+ *  Revision 1.12  2002/12/10 09:00:10  starvik
+ *  Merge of Linux 2.5.51
+ *
+ *  Revision 1.11  2002/12/05 07:53:10  starvik
+ *  Corrected constants used with btstq
+ *
+ *  Revision 1.10  2002/11/27 08:45:10  starvik
+ *  pid is in task_struct, not thread_info
+ *
+ *  Revision 1.9  2002/11/26 09:52:05  starvik
+ *  Added preemptive kernel scheduling (if CONFIG_PREEMPT)
+ *
+ *  Revision 1.8  2002/11/20 11:56:11  starvik
+ *  Merge of Linux 2.5.48
+ *
+ *  Revision 1.7  2002/11/18 13:02:42  starvik
+ *  Added fourth parameter to do_notify_resume
+ *  Minor cleanup
+ *
+ *  Revision 1.6  2002/11/11 10:37:50  starvik
+ *  Use new asm-offset defines
+ *  Modified for new location of current->work etc
+ *  Removed SYMBOL_NAME from syscalls
+ *  Added some new syscalls
+ *
+ *  Revision 1.5  2002/11/05 06:45:11  starvik
+ *  Merge of Linux 2.5.45
+ *
+ *  Revision 1.4  2002/02/05 15:41:31  bjornw
+ *  Rewritten to conform better to current 2.5 code (similar to arch/i386)
+ *
+ *  Revision 1.3  2002/01/21 15:22:20  bjornw
+ *  NICE_DOGGY fix from 2.4 arch/cris
+ *
+ *  Revision 1.37  2001/12/07 17:03:55  bjornw
+ *  Call a c-hook called watchdog_bite_hook instead of show_registers directly
+ *
+ *  Revision 1.36  2001/11/22 13:36:36  bjornw
+ *  * In ret_from_intr, check regs->dccr for usermode reentrance instead of
+ *    DCCR explicitely (because the latter might not reflect current reality)
+ *  * In mmu_bus_fault, set $r9 _after_ calling the C-code instead of before
+ *    since $r9 is call-clobbered and is potentially needed afterwards
+ *
+ *  Revision 1.35  2001/10/30 17:10:15  bjornw
+ *  Add some syscalls
+ *
+ *  Revision 1.34  2001/10/01 14:45:03  bjornw
+ *  Removed underscores and added register prefixes
+ *
+ *  Revision 1.33  2001/08/21 13:48:01  jonashg
+ *  Added fix by HP to avoid oops when doing a hard_reset_now.
+ *
+ *  Revision 1.32  2001/08/14 04:32:02  hp
+ *  In _resume, add comment why R9 is saved; don't sound like it's call-saved.
+ *
+ *  Revision 1.31  2001/07/25 16:07:42  bjornw
+ *  softirq_active/mask -> softirq_pending only
+ *
+ *  Revision 1.30  2001/07/05 01:03:32  hp
+ *  - include asm/errno.h to get ENOSYS.
+ *  - Use ENOSYS, not local constant LENOSYS; tweak comments.
+ *  - Explain why .include, not #include is used.
+ *  - Make oops-register-dump if watchdog bits and it's not expected.
+ *  - Don't jsr, use jump _hard_reset_now, and skip spurious nop.
+ *  - Use correct section attribute for section .rodata.
+ *  - Adjust sys_ni_syscall fill number.
+ *
+ *  Revision 1.29  2001/06/25 14:07:00  hp
+ *  	Fix review comment.
+ *  	* head.S: Use IO_STATE, IO_FIELD and IO_MASK constructs instead of
+ *  	magic numbers.  Add comment that -traditional must not be used.
+ *  	* entry.S (SYMBOL_NAME): Change redefinition to use ## concatenation.
+ *  	Correct and update comment.
+ *  	* Makefile (.S.o): Don't use -traditional.  Add comment why the
+ *  	toplevel rule can't be used (now that there's a reason).
+ *
+ *  Revision 1.28  2001/06/21 02:00:40  hp
+ *  	* entry.S: Include asm/unistd.h.
+ *  	(_sys_call_table): Use section .rodata, not .data.
+ *  	(_kernel_thread): Move from...
+ *  	* process.c: ... here.
+ *  	* entryoffsets.c (VAL): Break out from...
+ *  	(OF): Use VAL.
+ *  	(LCLONE_VM): New asmified value from CLONE_VM.
+ *
+ *  Revision 1.27  2001/05/29 11:25:27  markusl
+ *  In case of "spurious_interrupt", do hard_reset instead of hanging system in a loop...
+ *
+ *  Revision 1.26  2001/05/15 15:46:03  bjornw
+ *  Include config.h now that we use some CONFIG_ options
+ *
+ *  Revision 1.25  2001/05/15 05:38:47  hp
+ *  Tweaked code in _ret_from_sys_call
+ *
+ *  Revision 1.24  2001/05/15 05:27:49  hp
+ *  Save r9 in r1 over function call rather than on stack.
+ *
+ *  Revision 1.23  2001/05/15 05:10:00  hp
+ *  Generate entry.S structure offsets from C
+ *
+ *  Revision 1.22  2001/04/17 13:58:39  orjanf
+ *  * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB.
+ *
+ *  Revision 1.21  2001/04/17 11:33:29  orjanf
+ *  Updated according to review:
+ *  * Included asm/sv_addr_ag.h to get macro for internal register.
+ *  * Corrected comment regarding system call argument passing.
+ *  * Removed comment about instruction being in a delay slot.
+ *  * Added comment about SYMBOL_NAME macro.
+ *
+ *  Revision 1.20  2001/04/12 08:51:07  hp
+ *  - Add entry for sys_fcntl64.  In fact copy last piece from i386 including ...
+ *  - .rept to fill table to safe state with sys_ni_syscall.
+ *
+ *  Revision 1.19  2001/04/04 09:43:32  orjanf
+ *  * Moved do_sigtrap from traps.c to entry.S.
+ *  * LTASK_PID need not be global anymore.
+ *
+ *  Revision 1.18  2001/03/26 09:25:02  markusl
+ *  Updated after review, should now handle USB interrupts correctly.
+ *
+ *  Revision 1.17  2001/03/21 16:12:55  bjornw
+ *  * Always make room for the cpu status record in the frame, in order to
+ *    use the same framelength and layout for both mmu busfaults and normal
+ *    irqs. No need to check for the explicit CRIS_FRAME_FIXUP type anymore.
+ *  * Fixed bug with using addq for popping the stack in the epilogue - it
+ *    destroyed the flag register. Use instructions that don't affect the
+ *    flag register instead.
+ *  * Removed write to R_PORT_PA_DATA during spurious_interrupt
+ *
+ *  Revision 1.16  2001/03/20 19:43:02  bjornw
+ *  * Get rid of esp0 setting
+ *  * Give a 7th argument to a systemcall - the stackframe
+ *
+ *  Revision 1.15  2001/03/05 13:14:30  bjornw
+ *  Spelling fix
+ *
+ *  Revision 1.14  2001/02/23 08:36:36  perf
+ *  New ABI; syscallnr=r9, arg5=mof, arg6=srp.
+ *  Corrected tracesys call check.
+ *
+ *  Revision 1.13  2001/02/15 08:40:55  perf
+ *  H-P by way of perf;
+ *  - (_system_call): Don't read system call function address into r1.
+ *  - (RBFExit): There is no such thing as a null pop.  Adjust sp by addq.
+ *  - (_system_call): Don't use r10 and don't save and restore it.
+ *  - (THREAD_ESP0): New constant.
+ *  - (_system_call): Inline set_esp0.
+ *
+ *  Revision 1.12  2001/01/31 17:56:25  orjanf
+ *  Added definition of LTASK_PID and made it global.
+ *
+ *  Revision 1.11  2001/01/10 21:13:29  bjornw
+ *  SYMBOL_NAME is defined incorrectly for the compiler options we currently use
+ *
+ *  Revision 1.10  2000/12/18 23:47:56  bjornw
+ *  * Added syscall trace support (ptrace), completely untested of course
+ *  * Removed redundant check for NULL entries in syscall_table
+ *
+ *  Revision 1.9  2000/11/21 16:40:51  bjornw
+ *  * New frame type used when an SBFS frame needs to be popped without
+ *    actually restarting the instruction
+ *  * Enable interrupts in signal_return (they did so in x86, I hope it's a good
+ *    idea)
+ *
+ *  Revision 1.8  2000/11/17 16:53:35  bjornw
+ *  Added detection of frame-type in Rexit, so that mmu_bus_fault can
+ *  use ret_from_intr in the return-path to check for signals (like SEGV)
+ *  and other foul things that might have occurred during the fault.
+ *
+ *  Revision 1.7  2000/10/06 15:04:28  bjornw
+ *  Include mof in register savings
+ *
+ *  Revision 1.6  2000/09/12 16:02:44  bjornw
+ *  Linux-2.4.0-test7 derived updates
+ *
+ *  Revision 1.5  2000/08/17 15:35:15  bjornw
+ *  2.4.0-test6 changed local_irq_count and friends API
+ *
+ *  Revision 1.4  2000/08/02 13:59:30  bjornw
+ *  Removed olduname and uname from the syscall list
+ *
+ *  Revision 1.3  2000/07/31 13:32:58  bjornw
+ *  * Export ret_from_intr
+ *  * _resume updated (prev/last tjohejsan)
+ *  * timer_interrupt obsolete
+ *  * SIGSEGV detection in mmu_bus_fault temporarily disabled
+ *
+ *
+ */
+
+/*
+ * entry.S contains the system-call and fault low-level handling routines.
+ *
+ * NOTE: This code handles signal-recognition, which happens every time
+ * after a timer-interrupt and after each system call.
+ *
+ * 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
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <linux/sys.h>
+#include <asm/unistd.h>
+#include <asm/arch/sv_addr_ag.h>
+#include <asm/errno.h>
+#include <asm/thread_info.h>
+#include <asm/arch/offset.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+	;; functions exported from this file
+	
+	.globl system_call
+	.globl ret_from_intr
+	.globl ret_from_fork
+	.globl resume
+	.globl multiple_interrupt
+	.globl hwbreakpoint
+	.globl IRQ1_interrupt
+	.globl spurious_interrupt
+	.globl hw_bp_trigs
+	.globl mmu_bus_fault
+	.globl do_sigtrap
+	.globl gdb_handle_breakpoint
+	.globl sys_call_table
+	
+	;; below are various parts of system_call which are not in the fast-path
+	
+#ifdef CONFIG_PREEMPT	
+	; Check if preemptive kernel scheduling should be done
+_resume_kernel:
+	; Load current task struct
+	movs.w	-8192, $r0	;  THREAD_SIZE = 8192
+	and.d	$sp, $r0
+	move.d	[$r0+TI_preempt_count], $r10	;  Preemption disabled?
+	bne	_Rexit
+	nop
+_need_resched:
+	move.d	[$r0+TI_flags], $r10
+	btstq	TIF_NEED_RESCHED, $r10	; Check if need_resched is set
+	bpl	_Rexit
+	nop
+	; Ok, lets's do some preemptive kernel scheduling
+	move.d	PREEMPT_ACTIVE, $r10
+	move.d	$r10, [$r0+TI_preempt_count] ; Mark as active
+	ei
+	jsr	schedule
+	clear.d	[$r0+TI_preempt_count] ;  Mark as inactive
+	di
+	; Load new task struct
+	movs.w	-8192, $r0	;  THREAD_SIZE = 8192
+	and.d	$sp, $r0
+	; One more time (with new task)
+	ba	_need_resched
+	nop
+#else
+#define _resume_kernel _Rexit
+#endif	
+
+	; Called at exit from fork. schedule_tail must be called to drop
+	; spinlock if CONFIG_PREEMPT
+ret_from_fork:
+	jsr schedule_tail
+	ba  ret_from_sys_call
+	nop
+		
+ret_from_intr:
+	;; check for resched if preemptive kernel or if we're going back to user-mode 
+	;; this test matches the user_regs(regs) macro
+	;; we cannot simply test $dccr, because that does not necessarily
+	;; reflect what mode we'll return into.
+	
+	move.d	[$sp + PT_dccr], $r0; regs->dccr
+	btstq	8, $r0		; U-flag
+	bpl     _resume_kernel
+	; Note that di below is in delay slot 
+	
+_resume_userspace:
+	di			; so need_resched and sigpending don't change
+
+	movs.w	-8192, $r0	; THREAD_SIZE == 8192
+	and.d	$sp, $r0
+
+	move.d	[$r0+TI_flags], $r10	; current->work
+	and.d	_TIF_WORK_MASK, $r10	; is there any work to be done on return
+	bne	_work_pending
+	nop
+	ba	_Rexit
+	nop
+	
+	;; The system_call is called by a BREAK instruction, which works like
+	;; an interrupt call but it stores the return PC in BRP instead of IRP.
+	;; Since we dont really want to have two epilogues (one for system calls
+	;; and one for interrupts) we push the contents of BRP instead of IRP in the
+	;; system call prologue, to make it look like an ordinary interrupt on the
+	;; stackframe.
+	;;
+	;; Since we can't have system calls inside interrupts, it should not matter
+	;; that we don't stack IRP.
+	;; 
+	;; In r9 we have the wanted syscall number. Arguments come in r10,r11,r12,r13,mof,srp
+	;;
+	;; This function looks on the _surface_ like spaghetti programming, but it's
+	;; really designed so that the fast-path does not force cache-loading of non-used
+	;; instructions. Only the non-common cases cause the outlined code to run..
+
+system_call:
+	;; stack-frame similar to the irq heads, which is reversed in ret_from_sys_call
+	move	$brp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame
+	push	$srp
+	push	$dccr
+	push	$mof
+	subq	14*4, $sp		; make room for r0-r13
+	movem	$r13, [$sp]	; push r0-r13
+	push	$r10		; push orig_r10
+	clear.d [$sp=$sp-4]	; frametype == 0, normal stackframe
+	
+	movs.w	-ENOSYS, $r0
+	move.d	$r0, [$sp+PT_r10]	; put the default return value in r10 in the frame
+
+	;; check if this process is syscall-traced
+
+	movs.w	-8192, $r0	; THREAD_SIZE == 8192
+	and.d	$sp, $r0
+	
+	move.d	[$r0+TI_flags], $r0
+	btstq   TIF_SYSCALL_TRACE, $r0
+	bmi	_syscall_trace_entry
+	nop	
+
+_syscall_traced:	
+
+	;; check for sanity in the requested syscall number
+	
+	cmpu.w	NR_syscalls, $r9	
+	bcc	ret_from_sys_call
+	lslq	2, $r9		;  multiply by 4, in the delay slot
+
+	;; as a bonus 7th parameter, we give the location on the stack
+	;; of the register structure itself. some syscalls need this.
+
+	push	$sp
+	
+	;; the parameter carrying registers r10, r11, r12 and 13 are intact.
+	;; the fifth and sixth parameters (if any) was in mof and srp 
+	;; respectively, and we need to put them on the stack.
+
+	push	$srp
+	push	$mof
+	
+	jsr	[$r9+sys_call_table]	; actually do the system call
+	addq	3*4, $sp		; pop the mof, srp and regs parameters
+	move.d	$r10, [$sp+PT_r10]	; save the return value
+
+	moveq	1, $r9		; "parameter" to ret_from_sys_call to show it was a sys call
+	
+	;; fall through into ret_from_sys_call to return
+	
+ret_from_sys_call:
+	;; r9 is a parameter - if >=1 we came from a syscall, if 0, from an irq
+		
+	;; get the current task-struct pointer (see top for defs)
+
+	movs.w	-8192, $r0	; THREAD_SIZE == 8192 
+	and.d	$sp, $r0
+
+	di			; make sure need_resched and sigpending don't change
+	move.d	[$r0+TI_flags],$r1
+	and.d	_TIF_ALLWORK_MASK, $r1
+	bne	_syscall_exit_work
+	nop
+
+_Rexit:
+	;; this epilogue MUST match the prologues in multiple_interrupt, irq.h and ptregs.h
+	pop	$r10		; frametype
+	bne	_RBFexit	; was not CRIS_FRAME_NORMAL, handle otherwise
+	addq	4, $sp		; skip orig_r10, in delayslot
+	movem	[$sp+], $r13	; registers r0-r13
+	pop	$mof		; multiply overflow register 
+	pop	$dccr		; condition codes
+	pop	$srp		; subroutine return pointer
+	;; now we have a 4-word SBFS frame which we do not want to restore
+	;; using RBF since it was not stacked with SBFS. instead we would like to
+	;; just get the PC value to restart it with, and skip the rest of
+	;; the frame.
+	;; Also notice that it's important to use instructions here that
+	;; keep the interrupts disabled (since we've already popped DCCR)
+	move	[$sp=$sp+16], $p8; pop the SBFS frame from the sp
+	jmpu	[$sp-16]	; return through the irp field in the sbfs frame
+
+_RBFexit:
+	movem	[$sp+], $r13	; registers r0-r13, in delay slot
+	pop	$mof		; multiply overflow register 
+	pop	$dccr		; condition codes
+	pop	$srp		; subroutine return pointer
+	rbf	[$sp+]		; return by popping the CPU status
+
+	;; We get here after doing a syscall if extra work might need to be done
+	;; perform syscall exit tracing if needed
+	
+_syscall_exit_work:
+	;; $r0 contains current at this point and irq's are disabled
+
+	move.d  [$r0+TI_flags], $r1
+	btstq	TIF_SYSCALL_TRACE, $r1
+	bpl	_work_pending
+	nop
+	
+	ei
+
+	move.d	$r9, $r1	; preserve r9
+	jsr	do_syscall_trace
+	move.d	$r1, $r9
+	
+	ba	_resume_userspace
+	nop
+	
+_work_pending:
+	move.d  [$r0+TI_flags], $r1
+	btstq   TIF_NEED_RESCHED, $r1
+	bpl	_work_notifysig	; was neither trace nor sched, must be signal/notify
+	nop
+	
+_work_resched:
+	move.d	$r9, $r1	; preserve r9
+	jsr	schedule
+	move.d	$r1, $r9
+	di
+
+	move.d	[$r0+TI_flags], $r1
+	and.d	_TIF_WORK_MASK, $r1; ignore the syscall trace counter
+	beq	_Rexit
+	nop
+	btstq	TIF_NEED_RESCHED, $r1
+	bmi	_work_resched	; current->work.need_resched
+	nop
+
+_work_notifysig:
+	;; deal with pending signals and notify-resume requests
+
+	move.d	$r9, $r10	; do_notify_resume syscall/irq param
+	moveq	0, $r11		; oldset param - 0 in this case
+	move.d	$sp, $r12	; the regs param
+	move.d  $r1, $r13	; the thread_info_flags parameter
+	jsr	do_notify_resume
+	
+	ba _Rexit
+	nop
+
+	;; We get here as a sidetrack when we've entered a syscall with the
+	;; trace-bit set. We need to call do_syscall_trace and then continue
+	;; with the call.
+	
+_syscall_trace_entry:
+	;; PT_r10 in the frame contains -ENOSYS as required, at this point
+	
+	jsr	do_syscall_trace
+
+	;; now re-enter the syscall code to do the syscall itself
+	;; we need to restore $r9 here to contain the wanted syscall, and
+	;; the other parameter-bearing registers
+
+	move.d	[$sp+PT_r9], $r9
+	move.d	[$sp+PT_orig_r10], $r10  ; PT_r10 is already filled with -ENOSYS.
+	move.d	[$sp+PT_r11],      $r11
+	move.d	[$sp+PT_r12],      $r12
+	move.d	[$sp+PT_r13],      $r13
+	move	[$sp+PT_mof],      $mof
+	move	[$sp+PT_srp],      $srp
+	
+	ba	_syscall_traced
+	nop
+	
+	;; resume performs the actual task-switching, by switching stack pointers
+	;; input arguments: r10 = prev, r11 = next, r12 = thread offset in task struct
+	;; returns old current in r10
+	;;
+	;; TODO:  see the i386 version. The switch_to which calls resume in our version
+	;;        could really be an inline asm of this.
+
+resume:	
+	push	$srp		         ; we keep the old/new PC on the stack 
+	add.d	$r12, $r10		 ; r10 = current tasks tss
+	move	$dccr, [$r10+THREAD_dccr]; save irq enable state
+	di
+
+	move	$usp, [$r10+ THREAD_usp] ; save user-mode stackpointer
+	
+	;; See copy_thread for the reason why register R9 is saved.
+	subq	10*4, $sp
+	movem	$r9, [$sp]		 ; save non-scratch registers and R9.
+	
+	move.d	$sp, [$r10+THREAD_ksp]	 ; save the kernel stack pointer for the old task
+	move.d	$sp, $r10		 ; return last running task in r10
+	and.d   -8192, $r10	         ; get thread_info from stackpointer
+	move.d  [$r10+TI_task], $r10     ; get task  
+	add.d	$r12, $r11		 ; find the new tasks tss
+	move.d	[$r11+THREAD_ksp], $sp	 ; switch into the new stackframe by restoring kernel sp
+
+	movem	[$sp+], $r9		 ; restore non-scratch registers and R9.
+
+	move	[$r11+THREAD_usp], $usp ; restore user-mode stackpointer
+	
+	move	[$r11+THREAD_dccr], $dccr ; restore irq enable status
+	jump	[$sp+]		         ; restore PC
+
+	;; This is the MMU bus fault handler.
+	;; It needs to stack the CPU status and overall is different
+	;; from the other interrupt handlers.
+
+mmu_bus_fault:
+	;; For refills we try to do a quick page table lookup. If it is
+	;; a real fault we let the mm subsystem handle it.
+
+	;; the first longword in the sbfs frame was the interrupted PC
+	;; which fits nicely with the "IRP" slot in pt_regs normally used to
+	;; contain the return address. used by Oops to print kernel errors.
+	sbfs	[$sp=$sp-16]	; push the internal CPU status
+	push	$dccr
+	di
+	subq	2*4, $sp
+	movem	$r1, [$sp]
+	move.d  [R_MMU_CAUSE], $r1
+	;; ETRAX 100LX TR89 bugfix: if the second half of an unaligned
+	;; write causes a MMU-fault, it will not be restarted correctly.
+	;; This could happen if a write crosses a page-boundary and the
+	;; second page is not yet COW'ed or even loaded. The workaround
+	;; is to clear the unaligned bit in the CPU status record, so
+	;; that the CPU will rerun both the first and second halves of
+	;; the instruction. This will not have any sideeffects unless
+	;; the first half goes to any device or memory that can't be
+	;; written twice, and which is mapped through the MMU.
+	;;
+	;; We only need to do this for writes.
+	btstq	8, $r1		   ; Write access?
+	bpl	1f
+	nop
+	move.d	[$sp+16], $r0	   ; Clear unaligned bit in csrinstr
+	and.d	~(1<<5), $r0
+	move.d	$r0, [$sp+16]
+1:	btstq	12, $r1		   ; Refill?
+	bpl	2f
+	lsrq	PMD_SHIFT, $r1     ; Get PMD index into PGD (bit 24-31)
+	move.d  [current_pgd], $r0 ; PGD for the current process
+	move.d	[$r0+$r1.d], $r0   ; Get PMD
+	beq	2f
+	nop
+	and.w	PAGE_MASK, $r0	   ; Remove PMD flags
+	move.d  [R_MMU_CAUSE], $r1
+	lsrq	PAGE_SHIFT, $r1
+	and.d	0x7ff, $r1         ; Get PTE index into PMD (bit 13-24)
+	move.d	[$r0+$r1.d], $r1   ; Get PTE
+	beq	2f
+	nop
+	;; Store in TLB
+	move.d  $r1, [R_TLB_LO]
+	;; Return
+	movem	[$sp+], $r1
+	pop	$dccr
+	rbf	[$sp+]		; return by popping the CPU status
+
+2:	; PMD or PTE missing, let the mm subsystem fix it up.
+	movem	[$sp+], $r1
+	pop	$dccr
+
+	; Ok, not that easy, pass it on to the mm subsystem
+	; The MMU status record is now on the stack
+	push	$srp		; make a stackframe similar to pt_regs
+	push	$dccr
+	push	$mof
+	di
+	subq	14*4, $sp
+	movem	$r13, [$sp]
+	push	$r10		; dummy orig_r10
+	moveq	1, $r10
+	push	$r10		; frametype == 1, BUSFAULT frame type
+
+	move.d	$sp, $r10	; pt_regs argument to handle_mmu_bus_fault
+		
+	jsr	handle_mmu_bus_fault  ; in arch/cris/arch-v10/mm/fault.c
+
+	;; now we need to return through the normal path, we cannot just
+	;; do the RBFexit since we might have killed off the running
+	;; process due to a SEGV, scheduled due to a page blocking or
+	;; whatever.
+
+	moveq	0, $r9		; busfault is equivalent to an irq
+		
+	ba	ret_from_intr
+	nop
+		
+	;; special handlers for breakpoint and NMI
+hwbreakpoint:
+	push	$dccr
+	di
+	push	$r10
+	push	$r11
+	move.d	[hw_bp_trig_ptr],$r10
+	move	$brp,$r11
+	move.d	$r11,[$r10+]
+	move.d	$r10,[hw_bp_trig_ptr]
+1:	pop	$r11
+	pop	$r10
+	pop	$dccr
+	retb
+	nop
+	
+IRQ1_interrupt:
+
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+;; If we receive a watchdog interrupt while it is not expected, then set
+;; up a canonical frame and dump register contents before dying.
+
+	;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!!
+	move	$brp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame
+	push	$srp
+	push	$dccr
+	push	$mof
+	di
+	subq	14*4, $sp
+	movem	$r13, [$sp]
+	push	$r10		; push orig_r10
+	clear.d [$sp=$sp-4]	; frametype == 0, normal frame
+
+;; We don't check that we actually were bit by the watchdog as opposed to
+;; an external NMI, since there is currently no handler for external NMI.
+
+;; Check if we're waiting for reset to happen, as signalled by
+;; hard_reset_now setting cause_of_death to a magic value.  If so, just
+;; get stuck until reset happens.
+	.comm	cause_of_death, 4	;; Don't declare this anywhere.
+	move.d	[cause_of_death], $r10
+	cmp.d	0xbedead, $r10
+_killed_by_death:
+	beq	_killed_by_death
+	nop
+
+;; We'll see this in ksymoops dumps.
+Watchdog_bite:
+
+#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
+       ;; We just restart the watchdog here to be sure we dont get
+       ;; hit while printing the watchdogmsg below
+       ;; This restart is compatible with the rest of the C-code, so
+       ;; the C-code can keep restarting the watchdog after this point.
+       ;; The non-NICE_DOGGY code below though, disables the possibility
+       ;; to restart since it changes the watchdog key, to avoid any
+       ;; buggy loops etc. keeping the watchdog alive after this.
+       jsr     reset_watchdog
+#else
+
+;; We need to extend the 3.3ms after the NMI at watchdog bite, so we have
+;; time for an oops-dump over a 115k2 serial wire.  Another 100ms should do.
+
+;; Change the watchdog key to an arbitrary 3-bit value and restart the
+;; watchdog.
+#define WD_INIT 2
+	moveq	  IO_FIELD (R_WATCHDOG, key, WD_INIT), $r10
+	move.d	R_WATCHDOG, $r11
+
+	move.d	$r10, [$r11]
+	moveq	  IO_FIELD (R_WATCHDOG, key,				\
+			    IO_EXTRACT (R_WATCHDOG, key,		\
+					IO_MASK (R_WATCHDOG, key))	\
+			    ^ WD_INIT)					\
+		| IO_STATE (R_WATCHDOG, enable, start), $r10
+	move.d	$r10, [$r11]
+
+#endif
+	
+;; Note that we don't do "setf m" here (or after two necessary NOPs),
+;; since *not* doing that saves us from re-entrancy checks.  We don't want
+;; to get here again due to possible subsequent NMIs; we want the watchdog
+;; to reset us.
+
+	move.d	_watchdogmsg,$r10
+	jsr	printk
+
+	move.d	$sp, $r10
+	jsr	watchdog_bite_hook
+
+;; This nop is here so we see the "Watchdog_bite" label in ksymoops dumps
+;; rather than "spurious_interrupt".
+	nop
+;; At this point we drop down into spurious_interrupt, which will do a
+;; hard reset.
+
+	.section .rodata,"a"
+_watchdogmsg:
+	.ascii	"Oops: bitten by watchdog\n\0"
+	.previous
+
+#endif /* CONFIG_ETRAX_WATCHDOG and not CONFIG_SVINTO_SIM */
+
+spurious_interrupt:	
+	di
+	jump hard_reset_now
+
+	;; this handles the case when multiple interrupts arrive at the same time
+	;; we jump to the first set interrupt bit in a priority fashion
+	;; the hardware will call the unserved interrupts after the handler finishes
+	
+multiple_interrupt:
+	;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!!
+	move	$irp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame
+	push	$srp
+	push	$dccr
+	push	$mof
+	di
+	subq	14*4, $sp
+	movem	$r13, [$sp]
+	push	$r10		; push orig_r10
+	clear.d [$sp=$sp-4]	; frametype == 0, normal frame
+	
+	moveq	2, $r2		; first bit we care about is the timer0 irq
+	move.d	[R_VECT_MASK_RD], $r0; read the irq bits that triggered the multiple irq
+	move.d	$r0, [R_VECT_MASK_CLR] ; Block all active IRQs
+1:	
+	btst	$r2, $r0	; check for the irq given by bit r2
+	bpl	2f
+	move.d  $r2, $r10	; First argument to do_IRQ
+	move.d  $sp, $r11	; second argument to do_IRQ
+	jsr	do_IRQ
+2:
+	addq	1, $r2		; next vector bit
+	cmp.b	32, $r2
+	bne	1b	; process all irq's up to and including number 31
+	moveq	0, $r9  ; make ret_from_intr realise we came from an ir
+	
+	move.d	$r0, [R_VECT_MASK_SET] ;  Unblock all the IRQs
+	jump    ret_from_intr
+
+do_sigtrap:
+	;; 
+	;; SIGTRAP the process that executed the break instruction.
+	;; Make a frame that Rexit in entry.S expects.
+	;;
+	move	$brp, [$sp=$sp-16]	; Push BRP while faking a cpu status record.
+	push	$srp			; Push subroutine return pointer.
+	push	$dccr			; Push condition codes.
+	push	$mof			; Push multiply overflow reg.
+	di				; Need to disable irq's at this point.
+	subq	14*4, $sp		; Make room for r0-r13.
+	movem	$r13, [$sp]		; Push the r0-r13 registers.
+	push	$r10			; Push orig_r10.
+	clear.d	[$sp=$sp-4]		; Frametype - this is a normal stackframe.
+
+	movs.w	-8192,$r9		; THREAD_SIZE == 8192
+	and.d	$sp, $r9
+	move.d  [$r9+TI_task], $r10
+	move.d  [$r10+TASK_pid], $r10	; current->pid as arg1. 
+	moveq	5, $r11			; SIGTRAP as arg2.
+	jsr	sys_kill       
+	jump	ret_from_intr		; Use the return routine for interrupts.
+
+gdb_handle_breakpoint:	
+	push	$dccr
+	push	$r0
+#ifdef CONFIG_ETRAX_KGDB
+	move	$dccr, $r0		; U-flag not affected by previous insns. 
+	btstq	8, $r0			; Test the U-flag.
+	bmi	_ugdb_handle_breakpoint	; Go to user mode debugging. 
+	nop				; Empty delay slot (cannot pop r0 here). 
+	pop	$r0			; Restore r0.
+	ba	kgdb_handle_breakpoint	; Go to kernel debugging. 
+	pop	$dccr			; Restore dccr in delay slot.
+#endif
+	
+_ugdb_handle_breakpoint:	
+	move	$brp, $r0		; Use r0 temporarily for calculation.
+	subq	2, $r0			; Set to address of previous instruction.
+	move	$r0, $brp
+	pop	$r0			; Restore r0. 
+	ba	do_sigtrap		; SIGTRAP the offending process. 
+	pop	$dccr			; Restore dccr in delay slot.
+	
+	.data
+
+hw_bp_trigs:
+	.space 64*4
+hw_bp_trig_ptr:
+	.dword hw_bp_trigs
+
+	.section .rodata,"a"
+sys_call_table:	
+	.long sys_restart_syscall	/* 0 - old "setup()" system call, used for restarting */
+	.long sys_exit
+	.long sys_fork
+	.long sys_read
+	.long sys_write
+	.long sys_open		/* 5 */
+	.long sys_close
+	.long sys_waitpid
+	.long sys_creat
+	.long sys_link
+	.long sys_unlink	/* 10 */
+	.long sys_execve
+	.long sys_chdir
+	.long sys_time
+	.long sys_mknod
+	.long sys_chmod		/* 15 */
+	.long sys_lchown16
+	.long sys_ni_syscall	/* old break syscall holder */
+	.long sys_stat
+	.long sys_lseek
+	.long sys_getpid	/* 20 */
+	.long sys_mount
+	.long sys_oldumount
+	.long sys_setuid16
+	.long sys_getuid16
+	.long sys_stime		/* 25 */
+	.long sys_ptrace
+	.long sys_alarm
+	.long sys_fstat
+	.long sys_pause
+	.long sys_utime		/* 30 */
+	.long sys_ni_syscall	/* old stty syscall holder */
+	.long sys_ni_syscall	/* old gtty syscall holder */
+	.long sys_access
+	.long sys_nice
+	.long sys_ni_syscall	/* 35  old ftime syscall holder */
+	.long sys_sync
+	.long sys_kill
+	.long sys_rename
+	.long sys_mkdir
+	.long sys_rmdir		/* 40 */
+	.long sys_dup
+	.long sys_pipe
+	.long sys_times
+	.long sys_ni_syscall	/* old prof syscall holder */
+	.long sys_brk		/* 45 */
+	.long sys_setgid16
+	.long sys_getgid16
+	.long sys_signal
+	.long sys_geteuid16
+	.long sys_getegid16	/* 50 */
+	.long sys_acct
+	.long sys_umount	/* recycled never used phys( */
+	.long sys_ni_syscall	/* old lock syscall holder */
+	.long sys_ioctl
+	.long sys_fcntl		/* 55 */
+	.long sys_ni_syscall	/* old mpx syscall holder */
+	.long sys_setpgid
+	.long sys_ni_syscall	/* old ulimit syscall holder */
+	.long sys_ni_syscall	/* old sys_olduname holder */
+	.long sys_umask		/* 60 */
+	.long sys_chroot
+	.long sys_ustat
+	.long sys_dup2
+	.long sys_getppid
+	.long sys_getpgrp	/* 65 */
+	.long sys_setsid
+	.long sys_sigaction
+	.long sys_sgetmask
+	.long sys_ssetmask
+	.long sys_setreuid16	/* 70 */
+	.long sys_setregid16
+	.long sys_sigsuspend
+	.long sys_sigpending
+	.long sys_sethostname
+	.long sys_setrlimit	/* 75 */
+	.long sys_old_getrlimit
+	.long sys_getrusage
+	.long sys_gettimeofday
+	.long sys_settimeofday
+	.long sys_getgroups16	/* 80 */
+	.long sys_setgroups16
+	.long sys_select	/* was old_select in Linux/E100 */
+	.long sys_symlink
+	.long sys_lstat
+	.long sys_readlink	/* 85 */
+	.long sys_uselib
+	.long sys_swapon
+	.long sys_reboot
+	.long old_readdir
+	.long old_mmap		/* 90 */
+	.long sys_munmap
+	.long sys_truncate
+	.long sys_ftruncate
+	.long sys_fchmod
+	.long sys_fchown16	/* 95 */
+	.long sys_getpriority
+	.long sys_setpriority
+	.long sys_ni_syscall	/* old profil syscall holder */
+	.long sys_statfs
+	.long sys_fstatfs	/* 100 */
+	.long sys_ni_syscall	/* sys_ioperm in i386 */
+	.long sys_socketcall
+	.long sys_syslog
+	.long sys_setitimer
+	.long sys_getitimer	/* 105 */
+	.long sys_newstat
+	.long sys_newlstat
+	.long sys_newfstat
+	.long sys_ni_syscall	/* old sys_uname holder */
+	.long sys_ni_syscall	/* sys_iopl in i386 */
+	.long sys_vhangup
+	.long sys_ni_syscall	/* old "idle" system call */
+	.long sys_ni_syscall	/* vm86old in i386 */
+	.long sys_wait4
+	.long sys_swapoff	/* 115 */
+	.long sys_sysinfo
+	.long sys_ipc
+	.long sys_fsync
+	.long sys_sigreturn
+	.long sys_clone		/* 120 */
+	.long sys_setdomainname
+	.long sys_newuname
+	.long sys_ni_syscall	/* sys_modify_ldt */
+	.long sys_adjtimex
+	.long sys_mprotect	/* 125 */
+	.long sys_sigprocmask
+	.long sys_ni_syscall	/* old "create_module" */ 
+	.long sys_init_module
+	.long sys_delete_module
+	.long sys_ni_syscall	/* 130:	old "get_kernel_syms" */
+	.long sys_quotactl
+	.long sys_getpgid
+	.long sys_fchdir
+	.long sys_bdflush
+	.long sys_sysfs		/* 135 */
+	.long sys_personality
+	.long sys_ni_syscall	/* for afs_syscall */
+	.long sys_setfsuid16
+	.long sys_setfsgid16
+	.long sys_llseek	/* 140 */
+	.long sys_getdents
+	.long sys_select
+	.long sys_flock
+	.long sys_msync
+	.long sys_readv		/* 145 */
+	.long sys_writev
+	.long sys_getsid
+	.long sys_fdatasync
+	.long sys_sysctl
+	.long sys_mlock		/* 150 */
+	.long sys_munlock
+	.long sys_mlockall
+	.long sys_munlockall
+	.long sys_sched_setparam
+	.long sys_sched_getparam	/* 155 */
+	.long sys_sched_setscheduler
+	.long sys_sched_getscheduler
+	.long sys_sched_yield
+	.long sys_sched_get_priority_max
+	.long sys_sched_get_priority_min	/* 160 */
+	.long sys_sched_rr_get_interval
+	.long sys_nanosleep
+	.long sys_mremap
+	.long sys_setresuid16
+	.long sys_getresuid16	/* 165 */
+	.long sys_ni_syscall	/* sys_vm86 */
+	.long sys_ni_syscall	/* Old sys_query_module */
+	.long sys_poll
+	.long sys_nfsservctl
+	.long sys_setresgid16	/* 170 */
+	.long sys_getresgid16
+	.long sys_prctl
+	.long sys_rt_sigreturn
+	.long sys_rt_sigaction
+	.long sys_rt_sigprocmask	/* 175 */
+	.long sys_rt_sigpending
+	.long sys_rt_sigtimedwait
+	.long sys_rt_sigqueueinfo
+	.long sys_rt_sigsuspend
+	.long sys_pread64	/* 180 */
+	.long sys_pwrite64
+	.long sys_chown16
+	.long sys_getcwd
+	.long sys_capget
+	.long sys_capset	/* 185 */
+	.long sys_sigaltstack
+	.long sys_sendfile
+	.long sys_ni_syscall	/* streams1 */
+	.long sys_ni_syscall	/* streams2 */
+	.long sys_vfork		/* 190 */
+	.long sys_getrlimit
+	.long sys_mmap2
+	.long sys_truncate64
+	.long sys_ftruncate64
+	.long sys_stat64	/* 195 */
+	.long sys_lstat64
+	.long sys_fstat64
+	.long sys_lchown
+	.long sys_getuid
+	.long sys_getgid	/* 200 */
+	.long sys_geteuid
+	.long sys_getegid
+	.long sys_setreuid
+	.long sys_setregid
+	.long sys_getgroups	/* 205 */
+	.long sys_setgroups
+	.long sys_fchown
+	.long sys_setresuid
+	.long sys_getresuid
+	.long sys_setresgid	/* 210 */
+	.long sys_getresgid
+	.long sys_chown
+	.long sys_setuid
+	.long sys_setgid
+	.long sys_setfsuid	/* 215 */
+	.long sys_setfsgid
+	.long sys_pivot_root
+	.long sys_mincore
+	.long sys_madvise
+	.long sys_getdents64	/* 220 */
+	.long sys_fcntl64
+	.long sys_ni_syscall	/* reserved for TUX */
+	.long sys_ni_syscall
+	.long sys_gettid
+	.long sys_readahead	/* 225 */
+	.long sys_setxattr
+	.long sys_lsetxattr
+	.long sys_fsetxattr
+	.long sys_getxattr
+	.long sys_lgetxattr	/* 230 */
+	.long sys_fgetxattr
+	.long sys_listxattr
+	.long sys_llistxattr
+	.long sys_flistxattr
+	.long sys_removexattr	/* 235 */
+	.long sys_lremovexattr
+	.long sys_fremovexattr
+	.long sys_tkill
+	.long sys_sendfile64
+	.long sys_futex		/* 240 */
+	.long sys_sched_setaffinity
+	.long sys_sched_getaffinity
+	.long sys_ni_syscall	/* sys_set_thread_area */
+	.long sys_ni_syscall	/* sys_get_thread_area */
+	.long sys_io_setup	/* 245 */
+	.long sys_io_destroy
+	.long sys_io_getevents
+	.long sys_io_submit
+	.long sys_io_cancel
+	.long sys_fadvise64	/* 250 */
+	.long sys_ni_syscall
+	.long sys_exit_group
+	.long sys_lookup_dcookie
+	.long sys_epoll_create
+	.long sys_epoll_ctl	/* 255 */
+	.long sys_epoll_wait
+	.long sys_remap_file_pages
+ 	.long sys_set_tid_address
+ 	.long sys_timer_create
+ 	.long sys_timer_settime		/* 260 */
+ 	.long sys_timer_gettime
+ 	.long sys_timer_getoverrun
+ 	.long sys_timer_delete
+ 	.long sys_clock_settime
+ 	.long sys_clock_gettime		/* 265 */
+ 	.long sys_clock_getres
+ 	.long sys_clock_nanosleep
+	.long sys_statfs64
+	.long sys_fstatfs64	
+	.long sys_tgkill	/* 270 */
+	.long sys_utimes
+ 	.long sys_fadvise64_64
+	.long sys_ni_syscall	/* sys_vserver */
+	.long sys_ni_syscall	/* sys_mbind */
+	.long sys_ni_syscall	/* 275 sys_get_mempolicy */
+	.long sys_ni_syscall	/* sys_set_mempolicy */
+	.long sys_mq_open
+	.long sys_mq_unlink
+	.long sys_mq_timedsend
+	.long sys_mq_timedreceive	/* 280 */
+	.long sys_mq_notify
+	.long sys_mq_getsetattr
+	.long sys_ni_syscall		/* reserved for kexec */
+	.long sys_waitid
+
+        /*
+         * NOTE!! This doesn't have to be exact - we just have
+         * to make sure we have _enough_ of the "sys_ni_syscall"
+         * entries. Don't panic if you notice that this hasn't
+         * been shrunk every time we add a new system call.
+         */
+
+	.rept NR_syscalls-(.-sys_call_table)/4
+		.long sys_ni_syscall
+	.endr
+	
diff --git a/arch/cris/arch-v10/kernel/fasttimer.c b/arch/cris/arch-v10/kernel/fasttimer.c
new file mode 100644
index 0000000..4717f7a
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/fasttimer.c
@@ -0,0 +1,977 @@
+/* $Id: fasttimer.c,v 1.6 2004/05/14 10:18:39 starvik Exp $
+ * linux/arch/cris/kernel/fasttimer.c
+ *
+ * Fast timers for ETRAX100/ETRAX100LX
+ * This may be useful in other OS than Linux so use 2 space indentation...
+ *
+ * $Log: fasttimer.c,v $
+ * Revision 1.6  2004/05/14 10:18:39  starvik
+ * Export fast_timer_list
+ *
+ * Revision 1.5  2004/05/14 07:58:01  starvik
+ * Merge of changes from 2.4
+ *
+ * Revision 1.4  2003/07/04 08:27:41  starvik
+ * Merge of Linux 2.5.74
+ *
+ * Revision 1.3  2002/12/12 08:26:32  starvik
+ * Don't use C-comments inside CVS comments
+ *
+ * Revision 1.2  2002/12/11 15:42:02  starvik
+ * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/
+ *
+ * Revision 1.1  2002/11/18 07:58:06  starvik
+ * Fast timers (from Linux 2.4)
+ *
+ * Revision 1.5  2002/10/15 06:21:39  starvik
+ * Added call to init_waitqueue_head
+ *
+ * Revision 1.4  2002/05/28 17:47:59  johana
+ * Added del_fast_timer()
+ *
+ * Revision 1.3  2002/05/28 16:16:07  johana
+ * Handle empty fast_timer_list
+ *
+ * Revision 1.2  2002/05/27 15:38:42  johana
+ * Made it compile without warnings on Linux 2.4.
+ * (includes, wait_queue, PROC_FS and snprintf)
+ *
+ * Revision 1.1  2002/05/27 15:32:25  johana
+ * arch/etrax100/kernel/fasttimer.c v1.8 from the elinux tree.
+ *
+ * Revision 1.8  2001/11/27 13:50:40  pkj
+ * Disable interrupts while stopping the timer and while modifying the
+ * list of active timers in timer1_handler() as it may be interrupted
+ * by other interrupts (e.g., the serial interrupt) which may add fast
+ * timers.
+ *
+ * Revision 1.7  2001/11/22 11:50:32  pkj
+ * * Only store information about the last 16 timers.
+ * * proc_fasttimer_read() now uses an allocated buffer, since it
+ *   requires more space than just a page even for only writing the
+ *   last 16 timers. The buffer is only allocated on request, so
+ *   unless /proc/fasttimer is read, it is never allocated.
+ * * Renamed fast_timer_started to fast_timers_started to match
+ *   fast_timers_added and fast_timers_expired.
+ * * Some clean-up.
+ *
+ * Revision 1.6  2000/12/13 14:02:08  johana
+ * Removed volatile for fast_timer_list
+ *
+ * Revision 1.5  2000/12/13 13:55:35  johana
+ * Added DEBUG_LOG, added som cli() and cleanup
+ *
+ * Revision 1.4  2000/12/05 13:48:50  johana
+ * Added range check when writing proc file, modified timer int handling
+ *
+ * Revision 1.3  2000/11/23 10:10:20  johana
+ * More debug/logging possibilities.
+ * Moved GET_JIFFIES_USEC() to timex.h and time.c
+ *
+ * Revision 1.2  2000/11/01 13:41:04  johana
+ * Clean up and bugfixes.
+ * Created new do_gettimeofday_fast() that gets a timeval struct
+ * with time based on jiffies and *R_TIMER0_DATA, uses a table
+ * for fast conversion of timer value to microseconds.
+ * (Much faster the standard do_gettimeofday() and we don't really
+ * wan't to use the true time - we wan't the "uptime" so timers don't screw up
+ * when we change the time.
+ * TODO: Add efficient support for continuous timers as well.
+ *
+ * Revision 1.1  2000/10/26 15:49:16  johana
+ * Added fasttimer, highresolution timers.
+ *
+ * Copyright (C) 2000,2001 2002 Axis Communications AB, Lund, Sweden
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/delay.h>
+#include <asm/rtc.h>
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#include <asm/arch/svinto.h>
+#include <asm/fasttimer.h>
+#include <linux/proc_fs.h>
+
+
+#define DEBUG_LOG_INCLUDED
+#define FAST_TIMER_LOG
+//#define FAST_TIMER_TEST
+
+#define FAST_TIMER_SANITY_CHECKS
+
+#ifdef FAST_TIMER_SANITY_CHECKS
+#define SANITYCHECK(x) x
+static int sanity_failed = 0;
+#else
+#define SANITYCHECK(x)
+#endif
+
+#define D1(x)
+#define D2(x)
+#define DP(x)
+
+#define __INLINE__ inline
+
+static int fast_timer_running = 0;
+static int fast_timers_added = 0;
+static int fast_timers_started = 0;
+static int fast_timers_expired = 0;
+static int fast_timers_deleted = 0;
+static int fast_timer_is_init = 0;
+static int fast_timer_ints = 0;
+
+struct fast_timer *fast_timer_list = NULL;
+
+#ifdef DEBUG_LOG_INCLUDED
+#define DEBUG_LOG_MAX 128
+static const char * debug_log_string[DEBUG_LOG_MAX];
+static unsigned long debug_log_value[DEBUG_LOG_MAX];
+static int debug_log_cnt = 0;
+static int debug_log_cnt_wrapped = 0;
+
+#define DEBUG_LOG(string, value) \
+{ \
+  unsigned long log_flags; \
+  save_flags(log_flags); \
+  cli(); \
+  debug_log_string[debug_log_cnt] = (string); \
+  debug_log_value[debug_log_cnt] = (unsigned long)(value); \
+  if (++debug_log_cnt >= DEBUG_LOG_MAX) \
+  { \
+    debug_log_cnt = debug_log_cnt % DEBUG_LOG_MAX; \
+    debug_log_cnt_wrapped = 1; \
+  } \
+  restore_flags(log_flags); \
+}
+#else
+#define DEBUG_LOG(string, value)
+#endif
+
+
+/* The frequencies for index = clkselx number in R_TIMER_CTRL */
+#define NUM_TIMER_FREQ 15
+#define MAX_USABLE_TIMER_FREQ 7
+#define MAX_DELAY_US  853333L
+const unsigned long timer_freq_100[NUM_TIMER_FREQ] =
+{
+  3,   /* 0 3333 - 853333 us */
+  6,   /* 1 1666 - 426666 us */
+  12,  /* 2  833 - 213333 us */
+  24,  /* 3  416 - 106666 us */
+  48,  /* 4  208 -  53333 us */
+  96,  /* 5  104 -  26666 us */
+  192, /* 6   52 -  13333 us */
+  384, /* 7   26 -   6666 us */
+  576,
+  1152,
+  2304,
+  4608,
+  9216,
+  18432,
+  62500,
+  /* 15 = cascade */
+};
+#define NUM_TIMER_STATS 16
+#ifdef FAST_TIMER_LOG
+struct fast_timer timer_added_log[NUM_TIMER_STATS];
+struct fast_timer timer_started_log[NUM_TIMER_STATS];
+struct fast_timer timer_expired_log[NUM_TIMER_STATS];
+#endif
+
+int timer_div_settings[NUM_TIMER_STATS];
+int timer_freq_settings[NUM_TIMER_STATS];
+int timer_delay_settings[NUM_TIMER_STATS];
+
+/* Not true gettimeofday, only checks the jiffies (uptime) + useconds */
+void __INLINE__ do_gettimeofday_fast(struct timeval *tv)
+{
+  unsigned long sec = jiffies;
+  unsigned long usec = GET_JIFFIES_USEC();
+
+  usec += (sec % HZ) * (1000000 / HZ);
+  sec = sec / HZ;
+
+  if (usec > 1000000)
+  {
+    usec -= 1000000;
+    sec++;
+  }
+  tv->tv_sec = sec;
+  tv->tv_usec = usec;
+}
+
+int __INLINE__ timeval_cmp(struct timeval *t0, struct timeval *t1)
+{
+  if (t0->tv_sec < t1->tv_sec)
+  {
+    return -1;
+  }
+  else if (t0->tv_sec > t1->tv_sec)
+  {
+    return 1;
+  }
+  if (t0->tv_usec < t1->tv_usec)
+  {
+    return -1;
+  }
+  else if (t0->tv_usec > t1->tv_usec)
+  {
+    return 1;
+  }
+  return 0;
+}
+
+void __INLINE__ start_timer1(unsigned long delay_us)
+{
+  int freq_index = 0; /* This is the lowest resolution */
+  unsigned long upper_limit = MAX_DELAY_US;
+
+  unsigned long div;
+  /* Start/Restart the timer to the new shorter value */
+  /* t = 1/freq = 1/19200 = 53us
+   * T=div*t,  div = T/t = delay_us*freq/1000000
+   */
+#if 1 /* Adaptive timer settings */
+  while (delay_us < upper_limit && freq_index < MAX_USABLE_TIMER_FREQ)
+  {
+    freq_index++;
+    upper_limit >>= 1; /* Divide by 2 using shift */
+  }
+  if (freq_index > 0)
+  {
+    freq_index--;
+  }
+#else
+  freq_index = 6;
+#endif
+  div = delay_us * timer_freq_100[freq_index]/10000;
+  if (div < 2)
+  {
+    /* Maybe increase timer freq? */
+    div = 2;
+  }
+  if (div > 255)
+  {
+    div = 0; /* This means 256, the max the timer takes */
+    /* If a longer timeout than the timer can handle is used,
+     * then we must restart it when it goes off.
+     */
+  }
+
+  timer_div_settings[fast_timers_started % NUM_TIMER_STATS] = div;
+  timer_freq_settings[fast_timers_started % NUM_TIMER_STATS] = freq_index;
+  timer_delay_settings[fast_timers_started % NUM_TIMER_STATS] = delay_us;
+
+  D1(printk("start_timer1 : %d us freq: %i div: %i\n",
+            delay_us, freq_index, div));
+  /* Clear timer1 irq */
+  *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr);
+
+  /* Set timer values */
+  *R_TIMER_CTRL = r_timer_ctrl_shadow =
+    (r_timer_ctrl_shadow &
+     ~IO_MASK(R_TIMER_CTRL, timerdiv1) &
+     ~IO_MASK(R_TIMER_CTRL, tm1) &
+     ~IO_MASK(R_TIMER_CTRL, clksel1)) |
+    IO_FIELD(R_TIMER_CTRL, timerdiv1, div) |
+    IO_STATE(R_TIMER_CTRL, tm1, stop_ld) |
+    IO_FIELD(R_TIMER_CTRL, clksel1, freq_index ); /* 6=c19k2Hz */
+
+  /* Ack interrupt */
+  *R_TIMER_CTRL =  r_timer_ctrl_shadow |
+    IO_STATE(R_TIMER_CTRL, i1, clr);
+
+  /* Start timer */
+  *R_TIMER_CTRL = r_timer_ctrl_shadow =
+    (r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, tm1)) |
+    IO_STATE(R_TIMER_CTRL, tm1, run);
+
+  /* Enable timer1 irq */
+  *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer1, set);
+  fast_timers_started++;
+  fast_timer_running = 1;
+}
+
+/* In version 1.4 this function takes 27 - 50 us */
+void start_one_shot_timer(struct fast_timer *t,
+                          fast_timer_function_type *function,
+                          unsigned long data,
+                          unsigned long delay_us,
+                          const char *name)
+{
+  unsigned long flags;
+  struct fast_timer *tmp;
+
+  D1(printk("sft %s %d us\n", name, delay_us));
+
+  save_flags(flags);
+  cli();
+
+  do_gettimeofday_fast(&t->tv_set);
+  tmp = fast_timer_list;
+
+  SANITYCHECK({ /* Check so this is not in the list already... */
+    while (tmp != NULL)
+    {
+      if (tmp == t)
+      {
+        printk(KERN_WARNING
+               "timer name: %s data: 0x%08lX already in list!\n", name, data);
+        sanity_failed++;
+        return;
+      }
+      else
+      {
+        tmp = tmp->next;
+      }
+    }
+    tmp = fast_timer_list;
+  });
+
+  t->delay_us = delay_us;
+  t->function = function;
+  t->data = data;
+  t->name = name;
+
+  t->tv_expires.tv_usec = t->tv_set.tv_usec + delay_us % 1000000;
+  t->tv_expires.tv_sec  = t->tv_set.tv_sec  + delay_us / 1000000;
+  if (t->tv_expires.tv_usec > 1000000)
+  {
+    t->tv_expires.tv_usec -= 1000000;
+    t->tv_expires.tv_sec++;
+  }
+#ifdef FAST_TIMER_LOG
+  timer_added_log[fast_timers_added % NUM_TIMER_STATS] = *t;
+#endif
+  fast_timers_added++;
+
+  /* Check if this should timeout before anything else */
+  if (tmp == NULL || timeval_cmp(&t->tv_expires, &tmp->tv_expires) < 0)
+  {
+    /* Put first in list and modify the timer value */
+    t->prev = NULL;
+    t->next = fast_timer_list;
+    if (fast_timer_list)
+    {
+      fast_timer_list->prev = t;
+    }
+    fast_timer_list = t;
+#ifdef FAST_TIMER_LOG
+    timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t;
+#endif
+    start_timer1(delay_us);
+  } else {
+    /* Put in correct place in list */
+    while (tmp->next &&
+           timeval_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0)
+    {
+      tmp = tmp->next;
+    }
+    /* Insert t after tmp */
+    t->prev = tmp;
+    t->next = tmp->next;
+    if (tmp->next)
+    {
+      tmp->next->prev = t;
+    }
+    tmp->next = t;
+  }
+
+  D2(printk("start_one_shot_timer: %d us done\n", delay_us));
+
+  restore_flags(flags);
+} /* start_one_shot_timer */
+
+static inline int fast_timer_pending (const struct fast_timer * t)
+{
+  return (t->next != NULL) || (t->prev != NULL) || (t == fast_timer_list);
+}
+
+static inline int detach_fast_timer (struct fast_timer *t)
+{
+  struct fast_timer *next, *prev;
+  if (!fast_timer_pending(t))
+    return 0;
+  next = t->next;
+  prev = t->prev;
+  if (next)
+    next->prev = prev;
+  if (prev)
+    prev->next = next;
+  else
+    fast_timer_list = next;
+  fast_timers_deleted++;
+  return 1;
+}
+
+int del_fast_timer(struct fast_timer * t)
+{
+  unsigned long flags;
+  int ret;
+  
+  save_flags(flags);
+  cli();
+  ret = detach_fast_timer(t);
+  t->next = t->prev = NULL;
+  restore_flags(flags);
+  return ret;
+} /* del_fast_timer */
+
+
+/* Interrupt routines or functions called in interrupt context */
+
+/* Timer 1 interrupt handler */
+
+static irqreturn_t
+timer1_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+  struct fast_timer *t;
+  unsigned long flags;
+
+  save_flags(flags);
+  cli();
+
+  /* Clear timer1 irq */
+  *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr);
+
+  /* First stop timer, then ack interrupt */
+  /* Stop timer */
+  *R_TIMER_CTRL = r_timer_ctrl_shadow =
+    (r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, tm1)) |
+    IO_STATE(R_TIMER_CTRL, tm1, stop_ld);
+
+  /* Ack interrupt */
+  *R_TIMER_CTRL =  r_timer_ctrl_shadow | IO_STATE(R_TIMER_CTRL, i1, clr);
+
+  fast_timer_running = 0;
+  fast_timer_ints++;
+
+  restore_flags(flags);
+
+  t = fast_timer_list;
+  while (t)
+  {
+    struct timeval tv;
+
+    /* Has it really expired? */
+    do_gettimeofday_fast(&tv);
+    D1(printk("t: %is %06ius\n", tv.tv_sec, tv.tv_usec));
+
+    if (timeval_cmp(&t->tv_expires, &tv) <= 0)
+    {
+      /* Yes it has expired */
+#ifdef FAST_TIMER_LOG
+      timer_expired_log[fast_timers_expired % NUM_TIMER_STATS] = *t;
+#endif
+      fast_timers_expired++;
+
+      /* Remove this timer before call, since it may reuse the timer */
+      save_flags(flags);
+      cli();
+      if (t->prev)
+      {
+        t->prev->next = t->next;
+      }
+      else
+      {
+        fast_timer_list = t->next;
+      }
+      if (t->next)
+      {
+        t->next->prev = t->prev;
+      }
+      t->prev = NULL;
+      t->next = NULL;
+      restore_flags(flags);
+
+      if (t->function != NULL)
+      {
+        t->function(t->data);
+      }
+      else
+      {
+        DEBUG_LOG("!timer1 %i function==NULL!\n", fast_timer_ints);
+      }
+    }
+    else
+    {
+      /* Timer is to early, let's set it again using the normal routines */
+      D1(printk(".\n"));
+    }
+
+    save_flags(flags);
+    cli();
+    if ((t = fast_timer_list) != NULL)
+    {
+      /* Start next timer.. */
+      long us;
+      struct timeval tv;
+
+      do_gettimeofday_fast(&tv);
+      us = ((t->tv_expires.tv_sec - tv.tv_sec) * 1000000 +
+            t->tv_expires.tv_usec - tv.tv_usec);
+      if (us > 0)
+      {
+        if (!fast_timer_running)
+        {
+#ifdef FAST_TIMER_LOG
+          timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t;
+#endif
+          start_timer1(us);
+        }
+        restore_flags(flags);
+        break;
+      }
+      else
+      {
+        /* Timer already expired, let's handle it better late than never.
+         * The normal loop handles it
+         */
+        D1(printk("e! %d\n", us));
+      }
+    }
+    restore_flags(flags);
+  }
+
+  if (!t)
+  {
+    D1(printk("t1 stop!\n"));
+  }
+
+  return IRQ_HANDLED;
+}
+
+static void wake_up_func(unsigned long data)
+{
+#ifdef DECLARE_WAITQUEUE
+  wait_queue_head_t  *sleep_wait_p = (wait_queue_head_t*)data;
+#else
+  struct wait_queue **sleep_wait_p = (struct wait_queue **)data;
+#endif
+  wake_up(sleep_wait_p);
+}
+
+
+/* Useful API */
+
+void schedule_usleep(unsigned long us)
+{
+  struct fast_timer t;
+#ifdef DECLARE_WAITQUEUE
+  wait_queue_head_t sleep_wait;
+  init_waitqueue_head(&sleep_wait);
+  {
+  DECLARE_WAITQUEUE(wait, current);
+#else
+  struct wait_queue *sleep_wait = NULL;
+  struct wait_queue wait = { current, NULL };
+#endif
+
+  D1(printk("schedule_usleep(%d)\n", us));
+  add_wait_queue(&sleep_wait, &wait);
+  set_current_state(TASK_INTERRUPTIBLE);
+  start_one_shot_timer(&t, wake_up_func, (unsigned long)&sleep_wait, us,
+                       "usleep");
+  schedule();
+  set_current_state(TASK_RUNNING);
+  remove_wait_queue(&sleep_wait, &wait);
+  D1(printk("done schedule_usleep(%d)\n", us));
+#ifdef DECLARE_WAITQUEUE
+  }
+#endif  
+}
+
+#ifdef CONFIG_PROC_FS
+static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
+                       ,int *eof, void *data_unused);
+static struct proc_dir_entry *fasttimer_proc_entry;
+#endif /* CONFIG_PROC_FS */
+
+#ifdef CONFIG_PROC_FS
+
+/* This value is very much based on testing */
+#define BIG_BUF_SIZE (500 + NUM_TIMER_STATS * 300)
+
+static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
+                       ,int *eof, void *data_unused)
+{
+  unsigned long flags;
+  int i = 0;
+  int num_to_show;
+  struct timeval tv;
+  struct fast_timer *t, *nextt;
+  static char *bigbuf = NULL;
+  static unsigned long used;
+
+  if (!bigbuf && !(bigbuf = vmalloc(BIG_BUF_SIZE)))
+  {
+    used = 0;
+    bigbuf[0] = '\0';
+    return 0;
+  }
+
+  if (!offset || !used)
+  {
+    do_gettimeofday_fast(&tv);
+
+    used = 0;
+    used += sprintf(bigbuf + used, "Fast timers added:     %i\n",
+                    fast_timers_added);
+    used += sprintf(bigbuf + used, "Fast timers started:   %i\n",
+                    fast_timers_started);
+    used += sprintf(bigbuf + used, "Fast timer interrupts: %i\n",
+                    fast_timer_ints);
+    used += sprintf(bigbuf + used, "Fast timers expired:   %i\n",
+                    fast_timers_expired);
+    used += sprintf(bigbuf + used, "Fast timers deleted:   %i\n",
+                    fast_timers_deleted);
+    used += sprintf(bigbuf + used, "Fast timer running:    %s\n",
+                    fast_timer_running ? "yes" : "no");
+    used += sprintf(bigbuf + used, "Current time:          %lu.%06lu\n",
+                    (unsigned long)tv.tv_sec,
+                    (unsigned long)tv.tv_usec);
+#ifdef FAST_TIMER_SANITY_CHECKS
+    used += sprintf(bigbuf + used, "Sanity failed:         %i\n",
+                    sanity_failed);
+#endif
+    used += sprintf(bigbuf + used, "\n");
+
+#ifdef DEBUG_LOG_INCLUDED
+    {
+      int end_i = debug_log_cnt;
+      i = 0;
+
+      if (debug_log_cnt_wrapped)
+      {
+        i = debug_log_cnt;
+      }
+
+      while ((i != end_i || (debug_log_cnt_wrapped && !used)) &&
+             used+100 < BIG_BUF_SIZE)
+      {
+        used += sprintf(bigbuf + used, debug_log_string[i],
+                        debug_log_value[i]);
+        i = (i+1) % DEBUG_LOG_MAX;
+      }
+    }
+    used += sprintf(bigbuf + used, "\n");
+#endif
+
+    num_to_show = (fast_timers_started < NUM_TIMER_STATS ? fast_timers_started:
+                   NUM_TIMER_STATS);
+    used += sprintf(bigbuf + used, "Timers started: %i\n", fast_timers_started);
+    for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE) ; i++)
+    {
+      int cur = (fast_timers_started - i - 1) % NUM_TIMER_STATS;
+
+#if 1 //ndef FAST_TIMER_LOG
+      used += sprintf(bigbuf + used, "div: %i freq: %i delay: %i"
+                      "\n",
+                      timer_div_settings[cur],
+                      timer_freq_settings[cur],
+                      timer_delay_settings[cur]
+                      );
+#endif
+#ifdef FAST_TIMER_LOG
+      t = &timer_started_log[cur];
+      used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+                      "d: %6li us data: 0x%08lX"
+                      "\n",
+                      t->name,
+                      (unsigned long)t->tv_set.tv_sec,
+                      (unsigned long)t->tv_set.tv_usec,
+                      (unsigned long)t->tv_expires.tv_sec,
+                      (unsigned long)t->tv_expires.tv_usec,
+                      t->delay_us,
+                      t->data
+                      );
+#endif
+    }
+    used += sprintf(bigbuf + used, "\n");
+
+#ifdef FAST_TIMER_LOG
+    num_to_show = (fast_timers_added < NUM_TIMER_STATS ? fast_timers_added:
+                   NUM_TIMER_STATS);
+    used += sprintf(bigbuf + used, "Timers added: %i\n", fast_timers_added);
+    for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++)
+    {
+      t = &timer_added_log[(fast_timers_added - i - 1) % NUM_TIMER_STATS];
+      used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+                      "d: %6li us data: 0x%08lX"
+                      "\n",
+                      t->name,
+                      (unsigned long)t->tv_set.tv_sec,
+                      (unsigned long)t->tv_set.tv_usec,
+                      (unsigned long)t->tv_expires.tv_sec,
+                      (unsigned long)t->tv_expires.tv_usec,
+                      t->delay_us,
+                      t->data
+                      );
+    }
+    used += sprintf(bigbuf + used, "\n");
+
+    num_to_show = (fast_timers_expired < NUM_TIMER_STATS ? fast_timers_expired:
+                   NUM_TIMER_STATS);
+    used += sprintf(bigbuf + used, "Timers expired: %i\n", fast_timers_expired);
+    for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++)
+    {
+      t = &timer_expired_log[(fast_timers_expired - i - 1) % NUM_TIMER_STATS];
+      used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+                      "d: %6li us data: 0x%08lX"
+                      "\n",
+                      t->name,
+                      (unsigned long)t->tv_set.tv_sec,
+                      (unsigned long)t->tv_set.tv_usec,
+                      (unsigned long)t->tv_expires.tv_sec,
+                      (unsigned long)t->tv_expires.tv_usec,
+                      t->delay_us,
+                      t->data
+                      );
+    }
+    used += sprintf(bigbuf + used, "\n");
+#endif
+
+    used += sprintf(bigbuf + used, "Active timers:\n");
+    save_flags(flags);
+    cli();
+    t = fast_timer_list;
+    while (t != NULL && (used+100 < BIG_BUF_SIZE))
+    {
+      nextt = t->next;
+      restore_flags(flags);
+      used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+                      "d: %6li us data: 0x%08lX"
+/*                      " func: 0x%08lX" */
+                      "\n",
+                      t->name,
+                      (unsigned long)t->tv_set.tv_sec,
+                      (unsigned long)t->tv_set.tv_usec,
+                      (unsigned long)t->tv_expires.tv_sec,
+                      (unsigned long)t->tv_expires.tv_usec,
+                      t->delay_us,
+                      t->data
+/*                      , t->function */
+                      );
+      cli();
+      if (t->next != nextt)
+      {
+        printk(KERN_WARNING "timer removed!\n");
+      }
+      t = nextt;
+    }
+    restore_flags(flags);
+  }
+
+  if (used - offset < len)
+  {
+    len = used - offset;
+  }
+
+  memcpy(buf, bigbuf + offset, len);
+  *start = buf;
+  *eof = 1;
+
+  return len;
+}
+#endif /* PROC_FS */
+
+#ifdef FAST_TIMER_TEST
+static volatile unsigned long i = 0;
+static volatile int num_test_timeout = 0;
+static struct fast_timer tr[10];
+static int exp_num[10];
+
+static struct timeval tv_exp[100];
+
+static void test_timeout(unsigned long data)
+{
+  do_gettimeofday_fast(&tv_exp[data]);
+  exp_num[data] = num_test_timeout;
+
+  num_test_timeout++;
+}
+
+static void test_timeout1(unsigned long data)
+{
+  do_gettimeofday_fast(&tv_exp[data]);
+  exp_num[data] = num_test_timeout;
+  if (data < 7)
+  {
+    start_one_shot_timer(&tr[i], test_timeout1, i, 1000, "timeout1");
+    i++;
+  }
+  num_test_timeout++;
+}
+
+DP(
+static char buf0[2000];
+static char buf1[2000];
+static char buf2[2000];
+static char buf3[2000];
+static char buf4[2000];
+);
+
+static char buf5[6000];
+static int j_u[1000];
+
+static void fast_timer_test(void)
+{
+  int prev_num;
+  int j;
+
+  struct timeval tv, tv0, tv1, tv2;
+
+  printk("fast_timer_test() start\n");
+  do_gettimeofday_fast(&tv);
+
+  for (j = 0; j < 1000; j++)
+  {
+    j_u[j] = GET_JIFFIES_USEC();
+  }
+  for (j = 0; j < 100; j++)
+  {
+    do_gettimeofday_fast(&tv_exp[j]);
+  }
+  printk("fast_timer_test() %is %06i\n", tv.tv_sec, tv.tv_usec);
+
+  for (j = 0; j < 1000; j++)
+  {
+    printk("%i %i %i %i %i\n",j_u[j], j_u[j+1], j_u[j+2], j_u[j+3], j_u[j+4]);
+    j += 4;
+  }
+  for (j = 0; j < 100; j++)
+  {
+    printk("%i.%i %i.%i %i.%i %i.%i %i.%i\n",
+           tv_exp[j].tv_sec,tv_exp[j].tv_usec,
+           tv_exp[j+1].tv_sec,tv_exp[j+1].tv_usec,
+           tv_exp[j+2].tv_sec,tv_exp[j+2].tv_usec,
+           tv_exp[j+3].tv_sec,tv_exp[j+3].tv_usec,
+           tv_exp[j+4].tv_sec,tv_exp[j+4].tv_usec);
+    j += 4;
+  }
+  do_gettimeofday_fast(&tv0);
+  start_one_shot_timer(&tr[i], test_timeout, i, 50000, "test0");
+  DP(proc_fasttimer_read(buf0, NULL, 0, 0, 0));
+  i++;
+  start_one_shot_timer(&tr[i], test_timeout, i, 70000, "test1");
+  DP(proc_fasttimer_read(buf1, NULL, 0, 0, 0));
+  i++;
+  start_one_shot_timer(&tr[i], test_timeout, i, 40000, "test2");
+  DP(proc_fasttimer_read(buf2, NULL, 0, 0, 0));
+  i++;
+  start_one_shot_timer(&tr[i], test_timeout, i, 60000, "test3");
+  DP(proc_fasttimer_read(buf3, NULL, 0, 0, 0));
+  i++;
+  start_one_shot_timer(&tr[i], test_timeout1, i, 55000, "test4xx");
+  DP(proc_fasttimer_read(buf4, NULL, 0, 0, 0));
+  i++;
+  do_gettimeofday_fast(&tv1);
+
+  proc_fasttimer_read(buf5, NULL, 0, 0, 0);
+
+  prev_num = num_test_timeout;
+  while (num_test_timeout < i)
+  {
+    if (num_test_timeout != prev_num)
+    {
+      prev_num = num_test_timeout;
+    }
+  }
+  do_gettimeofday_fast(&tv2);
+  printk("Timers started    %is %06i\n", tv0.tv_sec, tv0.tv_usec);
+  printk("Timers started at %is %06i\n", tv1.tv_sec, tv1.tv_usec);
+  printk("Timers done       %is %06i\n", tv2.tv_sec, tv2.tv_usec);
+  DP(printk("buf0:\n");
+     printk(buf0);
+     printk("buf1:\n");
+     printk(buf1);
+     printk("buf2:\n");
+     printk(buf2);
+     printk("buf3:\n");
+     printk(buf3);
+     printk("buf4:\n");
+     printk(buf4);
+  );
+  printk("buf5:\n");
+  printk(buf5);
+
+  printk("timers set:\n");
+  for(j = 0; j<i; j++)
+  {
+    struct fast_timer *t = &tr[j];
+    printk("%-10s set: %6is %06ius exp: %6is %06ius "
+           "data: 0x%08X func: 0x%08X\n",
+           t->name,
+           t->tv_set.tv_sec,
+           t->tv_set.tv_usec,
+           t->tv_expires.tv_sec,
+           t->tv_expires.tv_usec,
+           t->data,
+           t->function
+           );
+
+    printk("           del: %6ius     did exp: %6is %06ius as #%i error: %6li\n",
+           t->delay_us,
+           tv_exp[j].tv_sec,
+           tv_exp[j].tv_usec,
+           exp_num[j],
+           (tv_exp[j].tv_sec - t->tv_expires.tv_sec)*1000000 + tv_exp[j].tv_usec - t->tv_expires.tv_usec);
+  }
+  proc_fasttimer_read(buf5, NULL, 0, 0, 0);
+  printk("buf5 after all done:\n");
+  printk(buf5);
+  printk("fast_timer_test() done\n");
+}
+#endif
+
+
+void fast_timer_init(void)
+{
+  /* For some reason, request_irq() hangs when called froom time_init() */
+  if (!fast_timer_is_init)
+  {
+#if 0 && defined(FAST_TIMER_TEST)
+    int i;
+#endif
+
+    printk(KERN_INFO "fast_timer_init()\n");
+
+#if 0 && defined(FAST_TIMER_TEST)
+    for (i = 0; i <= TIMER0_DIV; i++)
+    {
+      /* We must be careful not to get overflow... */
+      printk("%3i %6u\n", i, timer0_value_us[i]);
+    }
+#endif
+#ifdef CONFIG_PROC_FS
+   if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 )))
+     fasttimer_proc_entry->read_proc = proc_fasttimer_read;
+#endif /* PROC_FS */
+    if(request_irq(TIMER1_IRQ_NBR, timer1_handler, SA_SHIRQ,
+                   "fast timer int", NULL))
+    {
+      printk("err: timer1 irq\n");
+    }
+    fast_timer_is_init = 1;
+#ifdef FAST_TIMER_TEST
+    printk("do test\n");
+    fast_timer_test();
+#endif
+  }
+}
diff --git a/arch/cris/arch-v10/kernel/head.S b/arch/cris/arch-v10/kernel/head.S
new file mode 100644
index 0000000..2c1dd11
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/head.S
@@ -0,0 +1,882 @@
+/* $Id: head.S,v 1.7 2004/05/14 07:58:01 starvik Exp $
+ * 
+ * Head of the kernel - alter with care
+ *
+ * Copyright (C) 2000, 2001 Axis Communications AB
+ *
+ * Authors:	Bjorn Wesen (bjornw@axis.com)
+ * 
+ * $Log: head.S,v $
+ * Revision 1.7  2004/05/14 07:58:01  starvik
+ * Merge of changes from 2.4
+ *
+ * Revision 1.6  2003/04/28 05:31:46  starvik
+ * Added section attributes
+ *
+ * Revision 1.5  2002/12/11 15:42:02  starvik
+ * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/*.c
+ *
+ * Revision 1.4  2002/11/07 09:00:44  starvik
+ * Names changed for init sections
+ * init_task_union -> init_thread_union
+ *
+ * Revision 1.3  2002/02/05 15:38:23  bjornw
+ * Oops.. non-CRAMFS_MAGIC should jump over the copying, not into it...
+ *
+ * Revision 1.2  2001/12/18 13:35:19  bjornw
+ * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15).
+ *
+ * Revision 1.43  2001/11/08 15:09:43  starvik
+ * Only start MII clock if Ethernet is configured
+ *
+ * Revision 1.42  2001/11/08 14:37:34  starvik
+ * Start MII clock early to make sure that it is running at tranceiver reset
+ *
+ * Revision 1.41  2001/10/29 14:55:58  pkj
+ * Corrected pa$r0 to par0.
+ *
+ * Revision 1.40  2001/10/03 14:59:57  pkj
+ * Added support for resetting the Bluetooth hardware.
+ *
+ * Revision 1.39  2001/10/01 14:45:03  bjornw
+ * Removed underscores and added register prefixes
+ *
+ * Revision 1.38  2001/09/21 07:14:11  jonashg
+ * Made root filesystem (cramfs) use mtdblock driver when booting from flash.
+ *
+ * Revision 1.37  2001/09/11 13:44:29  orjanf
+ * Decouple usage of serial ports for debug and kgdb.
+ *
+ * Revision 1.36  2001/06/29 12:39:31  pkj
+ * Added support for mirroring the first flash to just below the
+ * second one, to make them look consecutive to cramfs.
+ *
+ * Revision 1.35  2001/06/25 14:07:00  hp
+ * 	Fix review comment.
+ * 	* head.S: Use IO_STATE, IO_FIELD and IO_MASK constructs instead of
+ * 	magic numbers.  Add comment that -traditional must not be used.
+ * 	* entry.S (SYMBOL_NAME): Change redefinition to use ## concatenation.
+ * 	Correct and update comment.
+ * 	* Makefile (.S.o): Don't use -traditional.  Add comment why the
+ * 	toplevel rule can't be used (now that there's a reason).
+ *
+ * Revision 1.34  2001/05/15 07:08:14  hp
+ * Tweak "notice" to reflect that both r8 r9 are used
+ *
+ * Revision 1.33  2001/05/15 06:40:05  hp
+ * Put bulk of code in .text.init, data in .data.init
+ *
+ * Revision 1.32  2001/05/15 06:18:56  hp
+ * Execute review comment: s/bcc/bhs/g; s/bcs/blo/g
+ *
+ * Revision 1.31  2001/05/15 06:08:40  hp
+ * Add sentence about autodetecting the bit31-MMU-bug
+ *
+ * Revision 1.30  2001/05/15 06:00:05  hp
+ * Update comment: LOW_MAP is not forced on xsim anymore.
+ *
+ * Revision 1.29  2001/04/18 12:51:59  orjanf
+ * * Reverted review change regarding the use of bcs/bcc.
+ * * Removed non-working LED-clearing code.
+ *
+ * Revision 1.28  2001/04/17 13:58:39  orjanf
+ * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB.
+ *
+ * Revision 1.27  2001/04/17 11:42:35  orjanf
+ * Changed according to review:
+ * * Added comment explaining memory map bug.
+ * * Changed bcs and bcc to blo and bhs, respectively.
+ * * Removed mentioning of Stallone and Olga boards.
+ *
+ * Revision 1.26  2001/04/06 12:31:07  jonashg
+ * Check for cramfs in flash before RAM instead of RAM before flash.
+ *
+ * Revision 1.25  2001/04/04 06:23:53  starvik
+ * Initialize DRAM if not already initialized
+ *
+ * Revision 1.24  2001/04/03 11:12:00  starvik
+ * Removed dram init (done by rescue or etrax100boot
+ * Corrected include
+ *
+ * Revision 1.23  2001/04/03 09:53:03  starvik
+ * Include hw_settings.S
+ *
+ * Revision 1.22  2001/03/26 14:23:26  bjornw
+ * Namechange of some config options
+ *
+ * Revision 1.21  2001/03/08 12:14:41  bjornw
+ * * Config name for ETRAX IDE was renamed
+ * * Removed G27 auto-setting when JULIETTE is chosen (need to make this
+ *   a new config option later)
+ *
+ * Revision 1.20  2001/02/23 12:47:56  bjornw
+ * MMU regs during LOW_MAP updated to reflect a newer reality
+ *
+ * Revision 1.19  2001/02/19 11:12:07  bjornw
+ * Changed comment header format
+ *
+ * Revision 1.18  2001/02/15 07:25:38  starvik
+ * Added support for synchronous serial ports
+ *
+ * Revision 1.17  2001/02/08 15:53:13  starvik
+ * Last commit removed some important ifdefs
+ *
+ * Revision 1.16  2001/02/08 15:20:38  starvik
+ * Include dram_init.S as inline
+ *
+ * Revision 1.15  2001/01/29 18:12:01  bjornw
+ * Corrected some comments
+ *
+ * Revision 1.14  2001/01/29 13:11:29  starvik
+ * Include dram_init.S (with DRAM/SDRAM initialization)
+ *
+ * Revision 1.13  2001/01/23 14:54:57  markusl
+ * Updated for USB
+ * i.e. added r_gen_config settings
+ *
+ * Revision 1.12  2001/01/19 16:16:29  perf
+ * Added temporary mapping of 0x0c->0x0c to avoid flash loading confusion.
+ * Renamed serial options from ETRAX100 to ETRAX.
+ *
+ * Revision 1.11  2001/01/16 16:31:38  bjornw
+ * * Changed name and semantics of running_from_flash to romfs_in_flash,
+ *   set by head.S to indicate to setup.c whether there is a cramfs image
+ *   after the kernels BSS or not. Should work for all three boot-cases
+ *   (DRAM with cramfs in DRAM, DRAM with cramfs in flash (compressed boot),
+ *    and flash with cramfs in flash)
+ *
+ * Revision 1.10  2001/01/16 14:12:21  bjornw
+ * * Check for cramfs start passed in r9 from the decompressor, if all other
+ *   cramfs options fail (if we boot from DRAM but don't find a cramfs image
+ *   after the kernel in DRAM, it is probably still in the flash)
+ * * Check magic in cramfs detection when booting from flash directly
+ *
+ * Revision 1.9  2001/01/15 17:17:02  bjornw
+ * * Corrected the code that detects the cramfs lengths
+ * * Added a comment saying that the above does not work due to other
+ *   reasons..
+ *
+ * Revision 1.8  2001/01/15 16:27:51  jonashg
+ * Made boot after flashing work.
+ * * end destination is __vmlinux_end in RAM.
+ * * _romfs_start moved because of virtual memory.
+ *
+ * Revision 1.7  2000/11/21 13:55:29  bjornw
+ * Use CONFIG_CRIS_LOW_MAP for the low VM map instead of explicit CPU type
+ *
+ * Revision 1.6  2000/10/06 12:36:55  bjornw
+ * Forgot swapper_pg_dir when changing memory map..
+ *
+ * Revision 1.5  2000/10/04 16:49:30  bjornw
+ * * Fixed memory mapping in LX
+ * * Check for cramfs instead of romfs
+ *
+ */
+	
+#include <linux/config.h>
+#define ASSEMBLER_MACROS_ONLY
+/* The IO_* macros use the ## token concatenation operator, so
+   -traditional must not be used when assembling this file.  */
+#include <asm/arch/sv_addr_ag.h>
+
+#define CRAMFS_MAGIC 0x28cd3d45
+#define RAM_INIT_MAGIC 0x56902387
+
+#define START_ETHERNET_CLOCK IO_STATE(R_NETWORK_GEN_CONFIG, enable, on) |\
+                             IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk)
+				
+	;; exported symbols
+		
+	.globl	etrax_irv
+	.globl	romfs_start
+	.globl	romfs_length
+	.globl	romfs_in_flash
+	.globl  swapper_pg_dir
+					
+	.text
+
+	;; This is the entry point of the kernel. We are in supervisor mode.
+	;; 0x00000000 if Flash, 0x40004000 if DRAM
+	;; since etrax actually starts at address 2 when booting from flash, we
+	;; put a nop (2 bytes) here first so we dont accidentally skip the di
+	;;
+	;; NOTICE! The registers r8 and r9 are used as parameters carrying
+	;; information from the decompressor (if the kernel was compressed). 
+	;; They should not be used in the code below until read.
+	
+	nop	
+	di
+
+	;; First setup the kseg_c mapping from where the kernel is linked
+	;; to 0x40000000 (where the actual DRAM resides) otherwise
+	;; we cannot do very much! See arch/cris/README.mm
+	;;
+	;; Notice that since we're potentially running at 0x00 or 0x40 right now,
+	;; we will get a fault as soon as we enable the MMU if we dont
+	;; temporarily map those segments linearily.
+	;;
+	;; Due to a bug in Etrax-100 LX version 1 we need to map the memory
+	;; slightly different.  The bug is that you can't remap bit 31 of
+	;; an address.  Though we can check the version register for
+	;; whether the bug is present, some constants would then have to
+	;; be variables, so we don't.  The drawback is that you can "only" map
+	;; 1G per process with CONFIG_CRIS_LOW_MAP.
+
+#ifdef CONFIG_CRIS_LOW_MAP
+	; kseg mappings, temporary map of 0xc0->0x40
+ 	move.d	  IO_FIELD (R_MMU_KBASE_HI, base_c, 4)		\
+		| IO_FIELD (R_MMU_KBASE_HI, base_b, 0xb)	\
+		| IO_FIELD (R_MMU_KBASE_HI, base_9, 9)		\
+		| IO_FIELD (R_MMU_KBASE_HI, base_8, 8), $r0
+	move.d	$r0, [R_MMU_KBASE_HI]
+
+	; temporary map of 0x40->0x40 and 0x60->0x40 
+ 	move.d	  IO_FIELD (R_MMU_KBASE_LO, base_6, 4)		\
+		| IO_FIELD (R_MMU_KBASE_LO, base_4, 4), $r0
+	move.d	$r0, [R_MMU_KBASE_LO]
+
+	; mmu enable, segs e,c,b,a,6,5,4,0 segment mapped
+ 	move.d	  IO_STATE (R_MMU_CONFIG, mmu_enable, enable)	\
+		| IO_STATE (R_MMU_CONFIG, inv_excp, enable)	\
+		| IO_STATE (R_MMU_CONFIG, acc_excp, enable)	\
+		| IO_STATE (R_MMU_CONFIG, we_excp, enable)	\
+		| IO_STATE (R_MMU_CONFIG, seg_f, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_e, seg)		\
+		| IO_STATE (R_MMU_CONFIG, seg_d, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_c, seg)		\
+		| IO_STATE (R_MMU_CONFIG, seg_b, seg)		\
+		| IO_STATE (R_MMU_CONFIG, seg_a, seg)		\
+		| IO_STATE (R_MMU_CONFIG, seg_9, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_8, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_7, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_6, seg)		\
+		| IO_STATE (R_MMU_CONFIG, seg_5, seg)		\
+		| IO_STATE (R_MMU_CONFIG, seg_4, seg)		\
+		| IO_STATE (R_MMU_CONFIG, seg_3, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_2, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_1, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_0, seg), $r0
+	move.d	$r0, [R_MMU_CONFIG]
+#else
+	; kseg mappings
+ 	move.d	  IO_FIELD (R_MMU_KBASE_HI, base_e, 8)		\
+		| IO_FIELD (R_MMU_KBASE_HI, base_c, 4)		\
+		| IO_FIELD (R_MMU_KBASE_HI, base_b, 0xb), $r0
+	move.d	$r0, [R_MMU_KBASE_HI]
+
+	; temporary map of 0x40->0x40 and 0x00->0x00 
+	move.d	  IO_FIELD (R_MMU_KBASE_LO, base_4, 4), $r0
+	move.d	$r0, [R_MMU_KBASE_LO]
+
+	; mmu enable, segs f,e,c,b,4,0 segment mapped
+ 	move.d	  IO_STATE (R_MMU_CONFIG, mmu_enable, enable)	\
+		| IO_STATE (R_MMU_CONFIG, inv_excp, enable)	\
+		| IO_STATE (R_MMU_CONFIG, acc_excp, enable)	\
+		| IO_STATE (R_MMU_CONFIG, we_excp, enable)	\
+		| IO_STATE (R_MMU_CONFIG, seg_f, seg)		\
+		| IO_STATE (R_MMU_CONFIG, seg_e, seg)		\
+		| IO_STATE (R_MMU_CONFIG, seg_d, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_c, seg)		\
+		| IO_STATE (R_MMU_CONFIG, seg_b, seg)		\
+		| IO_STATE (R_MMU_CONFIG, seg_a, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_9, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_8, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_7, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_6, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_5, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_4, seg)		\
+		| IO_STATE (R_MMU_CONFIG, seg_3, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_2, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_1, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_0, seg), $r0
+	move.d	$r0, [R_MMU_CONFIG]
+#endif
+
+	;; Now we need to sort out the segments and their locations in RAM or
+	;; Flash. The image in the Flash (or in DRAM) consists of 3 pieces:
+	;; 1) kernel text, 2) kernel data, 3) ROM filesystem image
+	;; But the linker has linked the kernel to expect this layout in
+	;; DRAM memory:
+	;; 1) kernel text, 2) kernel data, 3) kernel BSS
+	;; (the location of the ROM filesystem is determined by the krom driver)
+	;; If we boot this from Flash, we want to keep the ROM filesystem in
+	;; the flash, we want to copy the text and need to copy the data to DRAM.
+	;; But if we boot from DRAM, we need to move the ROMFS image
+	;; from its position after kernel data, to after kernel BSS, BEFORE the
+	;; kernel starts using the BSS area (since its "overlayed" with the ROMFS)
+	;;
+	;; In both cases, we start in un-cached mode, and need to jump into a
+	;; cached PC after we're done fiddling around with the segments.
+	;; 
+	;; arch/etrax100/etrax100.ld sets some symbols that define the start
+	;; and end of each segment.
+
+	;; Check if we start from DRAM or FLASH by testing PC
+	
+	move.d	$pc,$r0
+	and.d	0x7fffffff,$r0	; get rid of the non-cache bit
+	cmp.d	0x10000,$r0	; arbitrary... just something above this code
+	blo	_inflash0
+	nop
+
+	jump	_inram		; enter cached ram
+
+	;; Jumpgate for branches.
+_inflash0:
+	jump	_inflash
+
+	;; Put this in a suitable section where we can reclaim storage
+	;; after init.
+	.section ".init.text", "ax"
+_inflash:
+#ifdef CONFIG_ETRAX_ETHERNET	
+	;; Start MII clock to make sure it is running when tranceiver is reset
+	move.d START_ETHERNET_CLOCK, $r0
+	move.d $r0, [R_NETWORK_GEN_CONFIG]
+#endif
+
+	;; Set up waitstates etc according to kernel configuration.
+#ifndef CONFIG_SVINTO_SIM
+	move.d   CONFIG_ETRAX_DEF_R_WAITSTATES, $r0
+	move.d   $r0, [R_WAITSTATES]
+
+	move.d   CONFIG_ETRAX_DEF_R_BUS_CONFIG, $r0
+	move.d   $r0, [R_BUS_CONFIG]
+#endif
+
+	;; We need to initialze DRAM registers before we start using the DRAM
+
+	cmp.d	RAM_INIT_MAGIC, $r8	; Already initialized?
+	beq	_dram_init_finished
+	nop
+	
+#include "../lib/dram_init.S"
+
+_dram_init_finished:		
+	;; Copy text+data to DRAM
+	;; This is fragile - the calculation of r4 as the image size depends
+	;; on that the labels below actually are the first and last positions
+	;; in the linker-script.
+	;;
+	;; Then the locating of the cramfs image depends on the aforementioned
+	;; image being located in the flash at 0. This is most often not true,
+	;; thus the following does not work (normally there is a rescue-block
+	;; between the physical start of the flash and the flash-image start,
+	;; and when run with compression, the kernel is actually unpacked to
+	;; DRAM and we never get here in the first place :))
+	
+	moveq	0, $r0			; source
+	move.d	text_start, $r1		; destination
+	move.d	__vmlinux_end, $r2	; end destination
+	move.d	$r2, $r4
+	sub.d	$r1, $r4		; r4=__vmlinux_end in flash, used below
+1:	move.w	[$r0+], $r3
+	move.w	$r3, [$r1+]
+	cmp.d	$r2, $r1
+	blo	1b
+	nop
+
+	;; We keep the cramfs in the flash.
+	;; There might be none, but that does not matter because
+	;; we don't do anything than read some bytes here.
+
+	moveq	0, $r0
+	move.d	$r0, [romfs_length] ; default if there is no cramfs
+
+	move.d  [$r4], $r0	; cramfs_super.magic
+	cmp.d	CRAMFS_MAGIC, $r0
+	bne	1f
+	nop
+	move.d	[$r4 + 4], $r0	; cramfs_super.size
+	move.d	$r0, [romfs_length]
+#ifdef CONFIG_CRIS_LOW_MAP
+	add.d   0x50000000, $r4	; add flash start in virtual memory (cached)
+#else
+	add.d   0xf0000000, $r4	; add flash start in virtual memory (cached)
+#endif
+	move.d	$r4, [romfs_start]
+1:	
+	moveq	1, $r0
+	move.d	$r0, [romfs_in_flash]
+		
+	jump	_start_it	; enter code, cached this time
+
+_inram:
+	;; Move the ROM fs to after BSS end. This assumes that the cramfs
+	;; second longword contains the length of the cramfs
+
+	moveq	0, $r0
+	move.d	$r0, [romfs_length] ; default if there is no cramfs
+	
+	;; The kernel could have been unpacked to DRAM by the loader, but
+	;; the cramfs image could still be in the Flash directly after the
+	;; compressed kernel image. The loader passes the address of the
+	;; byte succeeding the last compressed byte in the flash in the
+	;; register r9 when starting the kernel. Check if r9 points to a
+	;; decent cramfs image!
+	;; (Notice that if this is not booted from the loader, r9 will be
+	;;  garbage but we do sanity checks on it, the chance that it points
+	;;  to a cramfs magic is small.. )
+	
+	cmp.d	0x0ffffff8, $r9
+	bhs	_no_romfs_in_flash	; r9 points outside the flash area
+	nop
+	move.d	[$r9], $r0	; cramfs_super.magic
+	cmp.d	CRAMFS_MAGIC, $r0
+	bne	_no_romfs_in_flash
+	nop
+	move.d	[$r9+4], $r0	; cramfs_super.length
+	move.d	$r0, [romfs_length]
+#ifdef CONFIG_CRIS_LOW_MAP
+	add.d   0x50000000, $r9	; add flash start in virtual memory (cached)
+#else
+	add.d   0xf0000000, $r9	; add flash start in virtual memory (cached)
+#endif
+	move.d	$r9, [romfs_start]
+
+	moveq	1, $r0
+	move.d	$r0, [romfs_in_flash]
+
+	jump	_start_it	; enter code, cached this time
+
+_no_romfs_in_flash:
+	
+	;; Check if there is a cramfs (magic value).
+	;; Notice that we check for cramfs magic value - which is
+	;; the "rom fs" we'll possibly use in 2.4 if not JFFS (which does
+	;; not need this mechanism anyway)
+
+	move.d	__vmlinux_end, $r0; the image will be after the vmlinux end address
+	move.d	[$r0], $r1	; cramfs assumes same endian on host/target
+	cmp.d	CRAMFS_MAGIC, $r1; magic value in cramfs superblock
+	bne	2f
+	nop
+
+	;; Ok. What is its size ? 
+	
+	move.d	[$r0 + 4], $r2	; cramfs_super.size (again, no need to swapwb)
+
+	;; We want to copy it to the end of the BSS
+
+	move.d	_end, $r1
+
+	;; Remember values so cramfs and setup can find this info
+
+	move.d	$r1, [romfs_start]	; new romfs location
+	move.d	$r2, [romfs_length]
+
+	;; We need to copy it backwards, since they can be overlapping
+
+	add.d	$r2, $r0
+	add.d	$r2, $r1
+		
+	;; Go ahead. Make my loop.
+
+	lsrq	1, $r2		; size is in bytes, we copy words
+
+1:	move.w	[$r0=$r0-2],$r3
+	move.w	$r3,[$r1=$r1-2]
+	subq	1, $r2
+	bne	1b
+	nop
+
+2:		
+	;; Dont worry that the BSS is tainted. It will be cleared later.
+
+	moveq	0, $r0
+	move.d	$r0, [romfs_in_flash]
+
+	jump	_start_it	; better skip the additional cramfs check below
+	
+_start_it:
+
+	;; the kernel stack is overlayed with the task structure for each
+	;; task. thus the initial kernel stack is in the same page as the
+	;; init_task (but starts in the top of the page, size 8192)
+	move.d	init_thread_union + 8192, $sp
+	move.d	ibr_start,$r0	; this symbol is set by the linker script 
+	move	$r0,$ibr
+	move.d	$r0,[etrax_irv]	; set the interrupt base register and pointer
+	
+	;; Clear BSS region, from _bss_start to _end
+
+	move.d	__bss_start, $r0
+	move.d	_end, $r1
+1:	clear.d	[$r0+]
+	cmp.d	$r1, $r0
+	blo	1b
+	nop
+	
+#ifdef CONFIG_BLK_DEV_ETRAXIDE
+	;; disable ATA before enabling it in genconfig below
+	moveq	0,$r0
+	move.d	$r0,[R_ATA_CTRL_DATA]
+	move.d	$r0,[R_ATA_TRANSFER_CNT]
+	move.d	$r0,[R_ATA_CONFIG]
+#if 0
+	move.d	R_PORT_G_DATA, $r1
+	move.d	$r0, [$r1]; assert ATA bus-reset
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	move.d	0x08000000,$r0
+	move.d	$r0,[$r1]
+#endif
+#endif
+
+#ifdef CONFIG_JULIETTE
+	;; configure external DMA channel 0 before enabling it in genconfig
+	
+	moveq	0,$r0
+	move.d	$r0,[R_EXT_DMA_0_ADDR]
+	; cnt enable, word size, output, stop, size 0
+	move.d	  IO_STATE (R_EXT_DMA_0_CMD, cnt, enable)	\
+		| IO_STATE (R_EXT_DMA_0_CMD, rqpol, ahigh)	\
+		| IO_STATE (R_EXT_DMA_0_CMD, apol, ahigh)	\
+		| IO_STATE (R_EXT_DMA_0_CMD, rq_ack, burst)	\
+		| IO_STATE (R_EXT_DMA_0_CMD, wid, word)		\
+		| IO_STATE (R_EXT_DMA_0_CMD, dir, output)	\
+		| IO_STATE (R_EXT_DMA_0_CMD, run, stop)		\
+		| IO_FIELD (R_EXT_DMA_0_CMD, trf_count, 0),$r0
+	move.d	$r0,[R_EXT_DMA_0_CMD]
+
+	;; reset dma4 and wait for completion
+	
+	moveq	IO_STATE (R_DMA_CH4_CMD, cmd, reset),$r0
+	move.b	$r0,[R_DMA_CH4_CMD]
+1:	move.b	[R_DMA_CH4_CMD],$r0
+	and.b	IO_MASK (R_DMA_CH4_CMD, cmd),$r0
+	cmp.b	IO_STATE (R_DMA_CH4_CMD, cmd, reset),$r0
+	beq	1b
+	nop
+
+	;; reset dma5 and wait for completion
+	
+	moveq	IO_STATE (R_DMA_CH5_CMD, cmd, reset),$r0
+	move.b	$r0,[R_DMA_CH5_CMD]
+1:	move.b	[R_DMA_CH5_CMD],$r0
+	and.b	IO_MASK (R_DMA_CH5_CMD, cmd),$r0
+	cmp.b	IO_STATE (R_DMA_CH5_CMD, cmd, reset),$r0
+	beq	1b
+	nop
+#endif	
+			
+	;; Etrax product HW genconfig setup
+
+	moveq	0,$r0
+#if (!defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT0)) \
+	&& !defined(CONFIG_DMA_MEMCPY)
+	; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA
+	or.d	  IO_STATE (R_GEN_CONFIG, dma7, serial0)	\
+		| IO_STATE (R_GEN_CONFIG, dma6, serial0),$r0
+#endif
+#if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT1)
+	; DMA channels 8 and 9 to ser1, kgdb doesnt want DMA
+	or.d	  IO_STATE (R_GEN_CONFIG, dma9, serial1)	\
+		| IO_STATE (R_GEN_CONFIG, dma8, serial1),$r0
+#endif	
+#ifdef CONFIG_DMA_MEMCPY
+	; 6/7 memory-memory DMA
+	or.d	  IO_STATE (R_GEN_CONFIG, dma7, intdma6)	\
+		| IO_STATE (R_GEN_CONFIG, dma6, intdma7),$r0
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+	; Enable serial port 2
+	or.w	IO_STATE (R_GEN_CONFIG, ser2, select),$r0
+#if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT2)
+	; DMA channels 2 and 3 to ser2, kgdb doesnt want DMA
+	or.d	  IO_STATE (R_GEN_CONFIG, dma3, serial2)	\
+		| IO_STATE (R_GEN_CONFIG, dma2, serial2),$r0
+#endif
+#endif
+#if defined(CONFIG_ETRAX_SERIAL_PORT3) || defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1)
+	; Enable serial port 3
+	or.w	IO_STATE (R_GEN_CONFIG, ser3, select),$r0
+#if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT3)
+	; DMA channels 4 and 5 to ser3, kgdb doesnt want DMA
+	or.d	  IO_STATE (R_GEN_CONFIG, dma5, serial3)	\
+		| IO_STATE (R_GEN_CONFIG, dma4, serial3),$r0
+#endif
+#endif
+#if defined(CONFIG_ETRAX_PARALLEL_PORT0) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE)
+	; parport 0 enabled using DMA 2/3
+	or.w	IO_STATE (R_GEN_CONFIG, par0, select),$r0
+#endif
+#if defined(CONFIG_ETRAX_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE)
+	; parport 1 enabled using DMA 4/5
+	or.w	IO_STATE (R_GEN_CONFIG, par1, select),$r0
+#endif
+#ifdef CONFIG_ETRAX_IDE
+	; DMA channels 2 and 3 to ATA, ATA enabled
+	or.d	  IO_STATE (R_GEN_CONFIG, dma3, ata)	\
+		| IO_STATE (R_GEN_CONFIG, dma2, ata)	\
+		| IO_STATE (R_GEN_CONFIG, ata, select),$r0
+#endif
+	
+#ifdef CONFIG_ETRAX_USB_HOST_PORT1
+	; Set the USB port 1 enable bit
+	or.d	IO_STATE (R_GEN_CONFIG, usb1, select),$r0
+#endif
+#ifdef CONFIG_ETRAX_USB_HOST_PORT2
+	; Set the USB port 2 enable bit
+	or.d	IO_STATE (R_GEN_CONFIG, usb2, select),$r0
+#endif
+#ifdef CONFIG_ETRAX_USB_HOST
+	; Connect DMA channels 8 and 9 to USB
+	and.d	(~(IO_MASK (R_GEN_CONFIG, dma9)		\
+		   | IO_MASK (R_GEN_CONFIG, dma8)))	\
+		| IO_STATE (R_GEN_CONFIG, dma9, usb)	\
+		| IO_STATE (R_GEN_CONFIG, dma8, usb),$r0
+#endif
+	
+#ifdef CONFIG_JULIETTE
+	; DMA channels 4 and 5 to EXTDMA0, for Juliette
+	or.d	  IO_STATE (R_GEN_CONFIG, dma5, extdma0)	\
+		| IO_STATE (R_GEN_CONFIG, dma4, extdma0),$r0
+#endif
+
+#if defined(CONFIG_ETRAX_DEF_R_PORT_G0_DIR_OUT)
+        or.d      IO_STATE (R_GEN_CONFIG, g0dir, out),$r0
+#endif
+
+#if defined(CONFIG_ETRAX_DEF_R_PORT_G8_15_DIR_OUT)
+        or.d      IO_STATE (R_GEN_CONFIG, g8_15dir, out),$r0
+#endif
+#if defined(CONFIG_ETRAX_DEF_R_PORT_G16_23_DIR_OUT)
+       or.d      IO_STATE (R_GEN_CONFIG, g16_23dir, out),$r0
+#endif
+
+#if defined(CONFIG_ETRAX_DEF_R_PORT_G24_DIR_OUT)
+       or.d      IO_STATE (R_GEN_CONFIG, g24dir, out),$r0
+#endif
+
+	move.d	$r0,[genconfig_shadow] ; init a shadow register of R_GEN_CONFIG
+
+#ifndef CONFIG_SVINTO_SIM
+	move.d	$r0,[R_GEN_CONFIG]
+
+#if 0
+	moveq	4,$r0
+	move.b	$r0,[R_DMA_CH6_CMD]	; reset (ser0 dma out)
+	move.b	$r0,[R_DMA_CH7_CMD]	; reset (ser0 dma in)
+1:	move.b	[R_DMA_CH6_CMD],$r0	; wait for reset cycle to finish
+	and.b	7,$r0
+	cmp.b	4,$r0
+	beq	1b
+	nop
+1:	move.b	[R_DMA_CH7_CMD],$r0	; wait for reset cycle to finish
+	and.b	7,$r0
+	cmp.b	4,$r0
+	beq	1b
+	nop
+#endif
+	
+	moveq	IO_STATE (R_DMA_CH8_CMD, cmd, reset),$r0
+	move.b	$r0,[R_DMA_CH8_CMD]	; reset (ser1 dma out)
+	move.b	$r0,[R_DMA_CH9_CMD]	; reset (ser1 dma in)
+1:	move.b	[R_DMA_CH8_CMD],$r0	; wait for reset cycle to finish
+	andq	IO_MASK (R_DMA_CH8_CMD, cmd),$r0
+	cmpq	IO_STATE (R_DMA_CH8_CMD, cmd, reset),$r0
+	beq	1b
+	nop
+1:	move.b	[R_DMA_CH9_CMD],$r0	; wait for reset cycle to finish
+	andq	IO_MASK (R_DMA_CH9_CMD, cmd),$r0
+	cmpq	IO_STATE (R_DMA_CH9_CMD, cmd, reset),$r0
+	beq	1b
+	nop
+
+	;; setup port PA and PB default initial directions and data
+	;; including their shadow registers
+		
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PA_DIR,$r0
+#if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_PA7)
+	or.b	IO_STATE (R_PORT_PA_DIR, dir7, output),$r0
+#endif
+	move.b	$r0,[port_pa_dir_shadow]
+	move.b	$r0,[R_PORT_PA_DIR]
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PA_DATA,$r0
+#if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_PA7)
+#if defined(CONFIG_BLUETOOTH_RESET_ACTIVE_HIGH)
+	and.b	~(1 << 7),$r0
+#else
+	or.b	(1 << 7),$r0
+#endif
+#endif
+	move.b	$r0,[port_pa_data_shadow]
+	move.b	$r0,[R_PORT_PA_DATA]
+	
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG,$r0
+	move.b	$r0,[port_pb_config_shadow]
+	move.b	$r0,[R_PORT_PB_CONFIG]
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_DIR,$r0
+#if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_PB5)
+	or.b	IO_STATE (R_PORT_PB_DIR, dir5, output),$r0
+#endif
+	move.b	$r0,[port_pb_dir_shadow]
+	move.b	$r0,[R_PORT_PB_DIR]
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_DATA,$r0
+#if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_PB5)
+#if defined(CONFIG_BLUETOOTH_RESET_ACTIVE_HIGH)
+	and.b	~(1 << 5),$r0
+#else
+	or.b	(1 << 5),$r0
+#endif
+#endif
+	move.b	$r0,[port_pb_data_shadow]
+	move.b	$r0,[R_PORT_PB_DATA]
+
+	moveq   0, $r0
+	move.d  $r0,[port_pb_i2c_shadow]
+	move.d  $r0, [R_PORT_PB_I2C]
+
+	moveq	0,$r0
+#if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_G10)
+#if defined(CONFIG_BLUETOOTH_RESET_ACTIVE_HIGH)
+	and.d	~(1 << 10),$r0
+#else
+	or.d	(1 << 10),$r0
+#endif
+#endif
+#if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_G11)
+#if defined(CONFIG_BLUETOOTH_RESET_ACTIVE_HIGH)
+	and.d	~(1 << 11),$r0
+#else
+	or.d	(1 << 11),$r0
+#endif
+#endif
+	move.d	$r0,[port_g_data_shadow]
+	move.d	$r0,[R_PORT_G_DATA]
+	
+	;; setup the serial port 0 at 115200 baud for debug purposes
+	
+	moveq	  IO_STATE (R_SERIAL0_XOFF, tx_stop, enable)		\
+		| IO_STATE (R_SERIAL0_XOFF, auto_xoff, disable)		\
+		| IO_FIELD (R_SERIAL0_XOFF, xoff_char, 0),$r0
+	move.d	$r0,[R_SERIAL0_XOFF] 
+
+	; 115.2kbaud for both transmit and receive
+	move.b	  IO_STATE (R_SERIAL0_BAUD, tr_baud, c115k2Hz)		\
+		| IO_STATE (R_SERIAL0_BAUD, rec_baud, c115k2Hz),$r0
+	move.b	$r0,[R_SERIAL0_BAUD]
+
+	; Set up and enable the serial0 receiver.
+	move.b	  IO_STATE (R_SERIAL0_REC_CTRL, dma_err, stop)		\
+		| IO_STATE (R_SERIAL0_REC_CTRL, rec_enable, enable)	\
+		| IO_STATE (R_SERIAL0_REC_CTRL, rts_, active)		\
+		| IO_STATE (R_SERIAL0_REC_CTRL, sampling, middle)	\
+		| IO_STATE (R_SERIAL0_REC_CTRL, rec_stick_par, normal)	\
+		| IO_STATE (R_SERIAL0_REC_CTRL, rec_par, even)		\
+		| IO_STATE (R_SERIAL0_REC_CTRL, rec_par_en, disable)	\
+		| IO_STATE (R_SERIAL0_REC_CTRL, rec_bitnr, rec_8bit),$r0
+	move.b	$r0,[R_SERIAL0_REC_CTRL] 
+	
+	; Set up and enable the serial0 transmitter.
+	move.b	  IO_FIELD (R_SERIAL0_TR_CTRL, txd, 0)			\
+		| IO_STATE (R_SERIAL0_TR_CTRL, tr_enable, enable)	\
+		| IO_STATE (R_SERIAL0_TR_CTRL, auto_cts, disabled)	\
+		| IO_STATE (R_SERIAL0_TR_CTRL, stop_bits, one_bit)	\
+		| IO_STATE (R_SERIAL0_TR_CTRL, tr_stick_par, normal)	\
+		| IO_STATE (R_SERIAL0_TR_CTRL, tr_par, even)		\
+		| IO_STATE (R_SERIAL0_TR_CTRL, tr_par_en, disable)	\
+		| IO_STATE (R_SERIAL0_TR_CTRL, tr_bitnr, tr_8bit),$r0
+	move.b	$r0,[R_SERIAL0_TR_CTRL]
+
+	;; setup the serial port 1 at 115200 baud for debug purposes
+	
+	moveq	  IO_STATE (R_SERIAL1_XOFF, tx_stop, enable)		\
+		| IO_STATE (R_SERIAL1_XOFF, auto_xoff, disable)		\
+		| IO_FIELD (R_SERIAL1_XOFF, xoff_char, 0),$r0
+	move.d	$r0,[R_SERIAL1_XOFF] 
+
+	; 115.2kbaud for both transmit and receive
+	move.b	  IO_STATE (R_SERIAL1_BAUD, tr_baud, c115k2Hz)		\
+		| IO_STATE (R_SERIAL1_BAUD, rec_baud, c115k2Hz),$r0
+	move.b	$r0,[R_SERIAL1_BAUD]
+
+	; Set up and enable the serial1 receiver.
+	move.b	  IO_STATE (R_SERIAL1_REC_CTRL, dma_err, stop)		\
+		| IO_STATE (R_SERIAL1_REC_CTRL, rec_enable, enable)	\
+		| IO_STATE (R_SERIAL1_REC_CTRL, rts_, active)		\
+		| IO_STATE (R_SERIAL1_REC_CTRL, sampling, middle)	\
+		| IO_STATE (R_SERIAL1_REC_CTRL, rec_stick_par, normal)	\
+		| IO_STATE (R_SERIAL1_REC_CTRL, rec_par, even)		\
+		| IO_STATE (R_SERIAL1_REC_CTRL, rec_par_en, disable)	\
+		| IO_STATE (R_SERIAL1_REC_CTRL, rec_bitnr, rec_8bit),$r0
+	move.b	$r0,[R_SERIAL1_REC_CTRL] 
+	
+	; Set up and enable the serial1 transmitter.
+	move.b	  IO_FIELD (R_SERIAL1_TR_CTRL, txd, 0)			\
+		| IO_STATE (R_SERIAL1_TR_CTRL, tr_enable, enable)	\
+		| IO_STATE (R_SERIAL1_TR_CTRL, auto_cts, disabled)	\
+		| IO_STATE (R_SERIAL1_TR_CTRL, stop_bits, one_bit)	\
+		| IO_STATE (R_SERIAL1_TR_CTRL, tr_stick_par, normal)	\
+		| IO_STATE (R_SERIAL1_TR_CTRL, tr_par, even)		\
+		| IO_STATE (R_SERIAL1_TR_CTRL, tr_par_en, disable)	\
+		| IO_STATE (R_SERIAL1_TR_CTRL, tr_bitnr, tr_8bit),$r0
+	move.b	$r0,[R_SERIAL1_TR_CTRL]
+
+	
+#ifdef CONFIG_ETRAX_SERIAL_PORT3	
+	;; setup the serial port 3 at 115200 baud for debug purposes
+	
+	moveq	  IO_STATE (R_SERIAL3_XOFF, tx_stop, enable)		\
+		| IO_STATE (R_SERIAL3_XOFF, auto_xoff, disable)		\
+		| IO_FIELD (R_SERIAL3_XOFF, xoff_char, 0),$r0
+	move.d	$r0,[R_SERIAL3_XOFF] 
+
+	; 115.2kbaud for both transmit and receive
+	move.b	  IO_STATE (R_SERIAL3_BAUD, tr_baud, c115k2Hz)		\
+		| IO_STATE (R_SERIAL3_BAUD, rec_baud, c115k2Hz),$r0
+	move.b	$r0,[R_SERIAL3_BAUD]
+
+	; Set up and enable the serial3 receiver.
+	move.b	  IO_STATE (R_SERIAL3_REC_CTRL, dma_err, stop)		\
+		| IO_STATE (R_SERIAL3_REC_CTRL, rec_enable, enable)	\
+		| IO_STATE (R_SERIAL3_REC_CTRL, rts_, active)		\
+		| IO_STATE (R_SERIAL3_REC_CTRL, sampling, middle)	\
+		| IO_STATE (R_SERIAL3_REC_CTRL, rec_stick_par, normal)	\
+		| IO_STATE (R_SERIAL3_REC_CTRL, rec_par, even)		\
+		| IO_STATE (R_SERIAL3_REC_CTRL, rec_par_en, disable)	\
+		| IO_STATE (R_SERIAL3_REC_CTRL, rec_bitnr, rec_8bit),$r0
+	move.b	$r0,[R_SERIAL3_REC_CTRL] 
+	
+	; Set up and enable the serial3 transmitter.
+	move.b	  IO_FIELD (R_SERIAL3_TR_CTRL, txd, 0)			\
+		| IO_STATE (R_SERIAL3_TR_CTRL, tr_enable, enable)	\
+		| IO_STATE (R_SERIAL3_TR_CTRL, auto_cts, disabled)	\
+		| IO_STATE (R_SERIAL3_TR_CTRL, stop_bits, one_bit)	\
+		| IO_STATE (R_SERIAL3_TR_CTRL, tr_stick_par, normal)	\
+		| IO_STATE (R_SERIAL3_TR_CTRL, tr_par, even)		\
+		| IO_STATE (R_SERIAL3_TR_CTRL, tr_par_en, disable)	\
+		| IO_STATE (R_SERIAL3_TR_CTRL, tr_bitnr, tr_8bit),$r0
+	move.b	$r0,[R_SERIAL3_TR_CTRL]
+#endif
+	
+#endif /* CONFIG_SVINTO_SIM */
+
+	jump	start_kernel	; jump into the C-function start_kernel in init/main.c
+		
+	.data
+etrax_irv:	
+	.dword	0
+romfs_start:
+	.dword	0
+romfs_length:
+	.dword	0
+romfs_in_flash:
+	.dword	0
+	
+	;; put some special pages at the beginning of the kernel aligned
+	;; to page boundaries - the kernel cannot start until after this
+
+#ifdef CONFIG_CRIS_LOW_MAP
+swapper_pg_dir = 0x60002000
+#else	
+swapper_pg_dir = 0xc0002000
+#endif
+
+	.section ".init.data", "aw"
+#include "../lib/hw_settings.S"
diff --git a/arch/cris/arch-v10/kernel/irq.c b/arch/cris/arch-v10/kernel/irq.c
new file mode 100644
index 0000000..b2f16d6
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/irq.c
@@ -0,0 +1,204 @@
+/* $Id: irq.c,v 1.2 2004/06/09 05:30:27 starvik Exp $
+ *
+ *	linux/arch/cris/kernel/irq.c
+ *
+ *      Copyright (c) 2000-2002 Axis Communications AB
+ *
+ *      Authors: Bjorn Wesen (bjornw@axis.com)
+ *
+ *      This file contains the interrupt vectors and some 
+ *      helper functions
+ *
+ */
+
+#include <asm/irq.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/config.h>
+
+irqvectptr irq_shortcuts[NR_IRQS]; /* vector of shortcut jumps after the irq prologue */
+
+/* don't use set_int_vector, it bypasses the linux interrupt handlers. it is
+ * global just so that the kernel gdb can use it.
+ */
+
+void
+set_int_vector(int n, irqvectptr addr)
+{
+	etrax_irv->v[n + 0x20] = (irqvectptr)addr;
+}
+
+/* the breakpoint vector is obviously not made just like the normal irq handlers
+ * but needs to contain _code_ to jump to addr.
+ *
+ * the BREAK n instruction jumps to IBR + n * 8
+ */
+
+void
+set_break_vector(int n, irqvectptr addr)
+{
+	unsigned short *jinstr = (unsigned short *)&etrax_irv->v[n*2];
+	unsigned long *jaddr = (unsigned long *)(jinstr + 1);
+
+	/* if you don't know what this does, do not touch it! */
+	
+	*jinstr = 0x0d3f;
+	*jaddr = (unsigned long)addr;
+
+	/* 00000026 <clrlop+1a> 3f0d82000000     jump  0x82 */
+}
+
+/*
+ * This builds up the IRQ handler stubs using some ugly macros in irq.h
+ *
+ * These macros create the low-level assembly IRQ routines that do all
+ * the operations that are needed. They are also written to be fast - and to
+ * disable interrupts as little as humanly possible.
+ *
+ */
+
+/* IRQ0 and 1 are special traps */
+void hwbreakpoint(void);
+void IRQ1_interrupt(void);
+BUILD_TIMER_IRQ(2, 0x04)       /* the timer interrupt is somewhat special */
+BUILD_IRQ(3, 0x08)
+BUILD_IRQ(4, 0x10)
+BUILD_IRQ(5, 0x20)
+BUILD_IRQ(6, 0x40)
+BUILD_IRQ(7, 0x80)
+BUILD_IRQ(8, 0x100)
+BUILD_IRQ(9, 0x200)
+BUILD_IRQ(10, 0x400)
+BUILD_IRQ(11, 0x800)
+BUILD_IRQ(12, 0x1000)
+BUILD_IRQ(13, 0x2000)
+void mmu_bus_fault(void);      /* IRQ 14 is the bus fault interrupt */
+void multiple_interrupt(void); /* IRQ 15 is the multiple IRQ interrupt */
+BUILD_IRQ(16, 0x10000)
+BUILD_IRQ(17, 0x20000)
+BUILD_IRQ(18, 0x40000)
+BUILD_IRQ(19, 0x80000)
+BUILD_IRQ(20, 0x100000)
+BUILD_IRQ(21, 0x200000)
+BUILD_IRQ(22, 0x400000)
+BUILD_IRQ(23, 0x800000)
+BUILD_IRQ(24, 0x1000000)
+BUILD_IRQ(25, 0x2000000)
+/* IRQ 26-30 are reserved */
+BUILD_IRQ(31, 0x80000000)
+ 
+/*
+ * Pointers to the low-level handlers 
+ */
+
+static void (*interrupt[NR_IRQS])(void) = {
+	NULL, NULL, IRQ2_interrupt, IRQ3_interrupt,
+	IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt,
+	IRQ8_interrupt, IRQ9_interrupt, IRQ10_interrupt, IRQ11_interrupt,
+	IRQ12_interrupt, IRQ13_interrupt, NULL, NULL,	
+	IRQ16_interrupt, IRQ17_interrupt, IRQ18_interrupt, IRQ19_interrupt,	
+	IRQ20_interrupt, IRQ21_interrupt, IRQ22_interrupt, IRQ23_interrupt,	
+	IRQ24_interrupt, IRQ25_interrupt, NULL, NULL, NULL, NULL, NULL,
+	IRQ31_interrupt
+};
+
+static void (*bad_interrupt[NR_IRQS])(void) = {
+        NULL, NULL,
+	NULL, bad_IRQ3_interrupt,
+	bad_IRQ4_interrupt, bad_IRQ5_interrupt,
+	bad_IRQ6_interrupt, bad_IRQ7_interrupt,
+	bad_IRQ8_interrupt, bad_IRQ9_interrupt,
+	bad_IRQ10_interrupt, bad_IRQ11_interrupt,
+	bad_IRQ12_interrupt, bad_IRQ13_interrupt,
+	NULL, NULL,
+	bad_IRQ16_interrupt, bad_IRQ17_interrupt,
+	bad_IRQ18_interrupt, bad_IRQ19_interrupt,
+	bad_IRQ20_interrupt, bad_IRQ21_interrupt,
+	bad_IRQ22_interrupt, bad_IRQ23_interrupt,
+	bad_IRQ24_interrupt, bad_IRQ25_interrupt,
+	NULL, NULL, NULL, NULL, NULL,
+	bad_IRQ31_interrupt
+};
+
+void arch_setup_irq(int irq)
+{
+  set_int_vector(irq, interrupt[irq]);
+}
+
+void arch_free_irq(int irq)
+{
+  set_int_vector(irq, bad_interrupt[irq]);
+}
+
+void weird_irq(void);
+void system_call(void);  /* from entry.S */
+void do_sigtrap(void); /* from entry.S */
+void gdb_handle_breakpoint(void); /* from entry.S */
+
+/* init_IRQ() is called by start_kernel and is responsible for fixing IRQ masks and
+   setting the irq vector table to point to bad_interrupt ptrs.
+*/
+
+void __init
+init_IRQ(void)
+{
+	int i;
+
+	/* clear all interrupt masks */
+
+#ifndef CONFIG_SVINTO_SIM
+	*R_IRQ_MASK0_CLR = 0xffffffff;
+	*R_IRQ_MASK1_CLR = 0xffffffff;
+	*R_IRQ_MASK2_CLR = 0xffffffff;
+#endif
+
+	*R_VECT_MASK_CLR = 0xffffffff;
+
+	/* clear the shortcut entry points */
+
+	for(i = 0; i < NR_IRQS; i++)
+		irq_shortcuts[i] = NULL;
+        
+        for (i = 0; i < 256; i++)
+               etrax_irv->v[i] = weird_irq;
+
+        /* the entries in the break vector contain actual code to be
+           executed by the associated break handler, rather than just a jump
+           address. therefore we need to setup a default breakpoint handler
+           for all breakpoints */
+
+	for (i = 0; i < 16; i++)
+                set_break_vector(i, do_sigtrap);
+        
+	/* set all etrax irq's to the bad handlers */
+	for (i = 2; i < NR_IRQS; i++)
+		set_int_vector(i, bad_interrupt[i]);
+        
+	/* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */
+
+	set_int_vector(15, multiple_interrupt);
+	
+	/* 0 and 1 which are special breakpoint/NMI traps */
+
+	set_int_vector(0, hwbreakpoint);
+	set_int_vector(1, IRQ1_interrupt);
+
+	/* and irq 14 which is the mmu bus fault handler */
+
+	set_int_vector(14, mmu_bus_fault);
+
+	/* setup the system-call trap, which is reached by BREAK 13 */
+
+	set_break_vector(13, system_call);
+
+        /* setup a breakpoint handler for debugging used for both user and
+           kernel mode debugging  (which is why it is not inside an ifdef
+           CONFIG_ETRAX_KGDB) */
+        set_break_vector(8, gdb_handle_breakpoint);
+
+#ifdef CONFIG_ETRAX_KGDB
+	/* setup kgdb if its enabled, and break into the debugger */
+	kgdb_init();
+	breakpoint();
+#endif
+}
diff --git a/arch/cris/arch-v10/kernel/kgdb.c b/arch/cris/arch-v10/kernel/kgdb.c
new file mode 100644
index 0000000..7d368c8
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/kgdb.c
@@ -0,0 +1,1568 @@
+/*!**************************************************************************
+*!
+*! FILE NAME  : kgdb.c
+*!
+*! DESCRIPTION: Implementation of the gdb stub with respect to ETRAX 100.
+*!              It is a mix of arch/m68k/kernel/kgdb.c and cris_stub.c.
+*!
+*!---------------------------------------------------------------------------
+*! HISTORY
+*!
+*! DATE         NAME            CHANGES
+*! ----         ----            -------
+*! Apr 26 1999  Hendrik Ruijter Initial version.
+*! May  6 1999  Hendrik Ruijter Removed call to strlen in libc and removed
+*!                              struct assignment as it generates calls to
+*!                              memcpy in libc.
+*! Jun 17 1999  Hendrik Ruijter Added gdb 4.18 support. 'X', 'qC' and 'qL'.
+*! Jul 21 1999  Bjorn Wesen     eLinux port
+*!
+*! $Log: kgdb.c,v $
+*! Revision 1.5  2004/10/07 13:59:08  starvik
+*! Corrected call to set_int_vector
+*!
+*! Revision 1.4  2003/04/09 05:20:44  starvik
+*! Merge of Linux 2.5.67
+*!
+*! Revision 1.3  2003/01/21 19:11:08  starvik
+*! Modified include path for new dir layout
+*!
+*! Revision 1.2  2002/11/19 14:35:24  starvik
+*! Changes from linux 2.4
+*! Changed struct initializer syntax to the currently prefered notation
+*!
+*! Revision 1.1  2001/12/17 13:59:27  bjornw
+*! Initial revision
+*!
+*! Revision 1.6  2001/10/09 13:10:03  matsfg
+*! Added $ on registers and removed some underscores
+*!
+*! Revision 1.5  2001/04/17 13:58:39  orjanf
+*! * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB.
+*!
+*! Revision 1.4  2001/02/23 13:45:19  bjornw
+*! config.h check
+*!
+*! Revision 1.3  2001/01/31 18:08:23  orjanf
+*! Removed kgdb_handle_breakpoint from being the break 8 handler.
+*!
+*! Revision 1.2  2001/01/12 14:22:25  orjanf
+*! Updated kernel debugging support to work with ETRAX 100LX.
+*!
+*! Revision 1.1  2000/07/10 16:25:21  bjornw
+*! Initial revision
+*!
+*! Revision 1.1.1.1  1999/12/03 14:57:31  bjornw
+*! * Initial version of arch/cris, the latest CRIS architecture with an MMU.
+*!   Mostly copied from arch/etrax100 with appropriate renames of files.
+*!   The mm/ subdir is copied from arch/i386.
+*!   This does not compile yet at all.
+*!
+*!
+*! Revision 1.4  1999/07/22 17:25:25  bjornw
+*! Dont wait for + in putpacket if we havent hit the initial breakpoint yet. Added a kgdb_init function which sets up the break and irq vectors.
+*!
+*! Revision 1.3  1999/07/21 19:51:18  bjornw
+*! Check if the interrupting char is a ctrl-C, ignore otherwise.
+*!
+*! Revision 1.2  1999/07/21 18:09:39  bjornw
+*! Ported to eLinux architecture, and added some kgdb documentation.
+*!
+*!
+*!---------------------------------------------------------------------------
+*!
+*! $Id: kgdb.c,v 1.5 2004/10/07 13:59:08 starvik Exp $
+*!
+*! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN
+*!
+*!**************************************************************************/
+/* @(#) cris_stub.c 1.3 06/17/99 */
+
+/*
+ *  kgdb usage notes:
+ *  -----------------
+ *
+ * If you select CONFIG_ETRAX_KGDB in the configuration, the kernel will be 
+ * built with different gcc flags: "-g" is added to get debug infos, and
+ * "-fomit-frame-pointer" is omitted to make debugging easier. Since the
+ * resulting kernel will be quite big (approx. > 7 MB), it will be stripped
+ * before compresion. Such a kernel will behave just as usually, except if
+ * given a "debug=<device>" command line option. (Only serial devices are
+ * allowed for <device>, i.e. no printers or the like; possible values are
+ * machine depedend and are the same as for the usual debug device, the one
+ * for logging kernel messages.) If that option is given and the device can be
+ * initialized, the kernel will connect to the remote gdb in trap_init(). The
+ * serial parameters are fixed to 8N1 and 115200 bps, for easyness of
+ * implementation.
+ *
+ * To start a debugging session, start that gdb with the debugging kernel
+ * image (the one with the symbols, vmlinux.debug) named on the command line.
+ * This file will be used by gdb to get symbol and debugging infos about the
+ * kernel. Next, select remote debug mode by
+ *    target remote <device>
+ * where <device> is the name of the serial device over which the debugged
+ * machine is connected. Maybe you have to adjust the baud rate by
+ *    set remotebaud <rate>
+ * or also other parameters with stty:
+ *    shell stty ... </dev/...
+ * If the kernel to debug has already booted, it waited for gdb and now
+ * connects, and you'll see a breakpoint being reported. If the kernel isn't
+ * running yet, start it now. The order of gdb and the kernel doesn't matter.
+ * Another thing worth knowing about in the getting-started phase is how to
+ * debug the remote protocol itself. This is activated with
+ *    set remotedebug 1
+ * gdb will then print out each packet sent or received. You'll also get some
+ * messages about the gdb stub on the console of the debugged machine.
+ *
+ * If all that works, you can use lots of the usual debugging techniques on
+ * the kernel, e.g. inspecting and changing variables/memory, setting
+ * breakpoints, single stepping and so on. It's also possible to interrupt the
+ * debugged kernel by pressing C-c in gdb. Have fun! :-)
+ *
+ * The gdb stub is entered (and thus the remote gdb gets control) in the
+ * following situations:
+ *
+ *  - If breakpoint() is called. This is just after kgdb initialization, or if
+ *    a breakpoint() call has been put somewhere into the kernel source.
+ *    (Breakpoints can of course also be set the usual way in gdb.)
+ *    In eLinux, we call breakpoint() in init/main.c after IRQ initialization.
+ *
+ *  - If there is a kernel exception, i.e. bad_super_trap() or die_if_kernel()
+ *    are entered. All the CPU exceptions are mapped to (more or less..., see
+ *    the hard_trap_info array below) appropriate signal, which are reported
+ *    to gdb. die_if_kernel() is usually called after some kind of access
+ *    error and thus is reported as SIGSEGV.
+ *
+ *  - When panic() is called. This is reported as SIGABRT.
+ *
+ *  - If C-c is received over the serial line, which is treated as
+ *    SIGINT.
+ *
+ * Of course, all these signals are just faked for gdb, since there is no
+ * signal concept as such for the kernel. It also isn't possible --obviously--
+ * to set signal handlers from inside gdb, or restart the kernel with a
+ * signal.
+ *
+ * Current limitations:
+ *
+ *  - While the kernel is stopped, interrupts are disabled for safety reasons
+ *    (i.e., variables not changing magically or the like). But this also
+ *    means that the clock isn't running anymore, and that interrupts from the
+ *    hardware may get lost/not be served in time. This can cause some device
+ *    errors...
+ *
+ *  - When single-stepping, only one instruction of the current thread is
+ *    executed, but interrupts are allowed for that time and will be serviced
+ *    if pending. Be prepared for that.
+ *
+ *  - All debugging happens in kernel virtual address space. There's no way to
+ *    access physical memory not mapped in kernel space, or to access user
+ *    space. A way to work around this is using get_user_long & Co. in gdb
+ *    expressions, but only for the current process.
+ *
+ *  - Interrupting the kernel only works if interrupts are currently allowed,
+ *    and the interrupt of the serial line isn't blocked by some other means
+ *    (IPL too high, disabled, ...)
+ *
+ *  - The gdb stub is currently not reentrant, i.e. errors that happen therein
+ *    (e.g. accessing invalid memory) may not be caught correctly. This could
+ *    be removed in future by introducing a stack of struct registers.
+ *
+ */
+
+/*
+ *  To enable debugger support, two things need to happen.  One, a
+ *  call to kgdb_init() 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(). 
+ *
+ *    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 <linux/delay.h>
+#include <linux/linkage.h>
+
+#include <asm/setup.h>
+#include <asm/ptrace.h>
+
+#include <asm/arch/svinto.h>
+#include <asm/irq.h>
+
+static int kgdb_started = 0;
+
+/********************************* Register image ****************************/
+/* Use the order of registers as defined in "AXIS ETRAX CRIS Programmer's
+   Reference", p. 1-1, with the additional register definitions of the
+   ETRAX 100LX in cris-opc.h.
+   There are 16 general 32-bit registers, R0-R15, where R14 is the stack
+   pointer, SP, and R15 is the program counter, PC.
+   There are 16 special registers, P0-P15, where three of the unimplemented
+   registers, P0, P4 and P8, are reserved as zero-registers. A read from
+   any of these registers returns zero and a write has no effect. */
+
+typedef
+struct register_image
+{
+	/* Offset */
+	unsigned int     r0;   /* 0x00 */
+	unsigned int     r1;   /* 0x04 */
+	unsigned int     r2;   /* 0x08 */
+	unsigned int     r3;   /* 0x0C */
+	unsigned int     r4;   /* 0x10 */
+	unsigned int     r5;   /* 0x14 */
+	unsigned int     r6;   /* 0x18 */
+	unsigned int     r7;   /* 0x1C */
+	unsigned int     r8;   /* 0x20 Frame pointer */
+	unsigned int     r9;   /* 0x24 */
+	unsigned int    r10;   /* 0x28 */
+	unsigned int    r11;   /* 0x2C */
+	unsigned int    r12;   /* 0x30 */
+	unsigned int    r13;   /* 0x34 */
+	unsigned int     sp;   /* 0x38 Stack pointer */
+	unsigned int     pc;   /* 0x3C Program counter */
+
+        unsigned char    p0;   /* 0x40 8-bit zero-register */
+	unsigned char    vr;   /* 0x41 Version register */
+
+        unsigned short   p4;   /* 0x42 16-bit zero-register */
+	unsigned short  ccr;   /* 0x44 Condition code register */
+	
+	unsigned int    mof;   /* 0x46 Multiply overflow register */
+	
+        unsigned int     p8;   /* 0x4A 32-bit zero-register */
+	unsigned int    ibr;   /* 0x4E Interrupt base register */
+	unsigned int    irp;   /* 0x52 Interrupt return pointer */
+	unsigned int    srp;   /* 0x56 Subroutine return pointer */
+	unsigned int    bar;   /* 0x5A Breakpoint address register */
+	unsigned int   dccr;   /* 0x5E Double condition code register */
+	unsigned int    brp;   /* 0x62 Breakpoint return pointer (pc in caller) */
+	unsigned int    usp;   /* 0x66 User mode stack pointer */
+} registers;
+
+/************** Prototypes for local library functions ***********************/
+
+/* Copy of strcpy from libc. */
+static char *gdb_cris_strcpy (char *s1, const char *s2);
+
+/* Copy of strlen from libc. */
+static int gdb_cris_strlen (const char *s);
+
+/* Copy of memchr from libc. */
+static void *gdb_cris_memchr (const void *s, int c, int n);
+
+/* Copy of strtol from libc. Does only support base 16. */
+static int gdb_cris_strtol (const char *s, char **endptr, int base);
+
+/********************** Prototypes for local functions. **********************/
+/* Copy the content of a register image into another. The size n is
+   the size of the register image. Due to struct assignment generation of
+   memcpy in libc. */
+static void copy_registers (registers *dptr, registers *sptr, int n);
+
+/* Copy the stored registers from the stack. Put the register contents
+   of thread thread_id in the struct reg. */
+static void copy_registers_from_stack (int thread_id, registers *reg);
+
+/* Copy the registers to the stack. Put the register contents of thread
+   thread_id from struct reg to the stack. */
+static void copy_registers_to_stack (int thread_id, registers *reg);
+
+/* Write a value to a specified register regno in the register image
+   of the current thread. */
+static int write_register (int regno, char *val);
+
+/* Write a value to a specified register in the stack of a thread other
+   than the current thread. */
+static write_stack_register (int thread_id, int regno, char *valptr);
+
+/* Read a value from a specified register in the register image. Returns the
+   status of the read operation. The register value is returned in valptr. */
+static int read_register (char regno, unsigned int *valptr);
+
+/* Serial port, reads one character. ETRAX 100 specific. from debugport.c */
+int getDebugChar (void);
+
+/* Serial port, writes one character. ETRAX 100 specific. from debugport.c */
+void putDebugChar (int val);
+
+void enableDebugIRQ (void);
+
+/* Returns the character equivalent of a nibble, bit 7, 6, 5, and 4 of a byte,
+   represented by int x. */
+static char highhex (int x);
+
+/* Returns the character equivalent of a nibble, bit 3, 2, 1, and 0 of a byte,
+   represented by int x. */
+static char lowhex (int x);
+
+/* Returns the integer equivalent of a hexadecimal character. */
+static int hex (char ch);
+
+/* Convert the memory, pointed to by mem into hexadecimal representation.
+   Put the result in buf, and return a pointer to the last character
+   in buf (null). */
+static char *mem2hex (char *buf, unsigned char *mem, int count);
+
+/* Convert the array, in hexadecimal representation, pointed to by buf into
+   binary representation. Put the result in mem, and return a pointer to
+   the character after the last byte written. */
+static unsigned char *hex2mem (unsigned char *mem, char *buf, int count);
+
+/* Put the content of the array, in binary representation, pointed to by buf
+   into memory pointed to by mem, and return a pointer to
+   the character after the last byte written. */
+static unsigned char *bin2mem (unsigned char *mem, unsigned char *buf, int count);
+
+/* Await the sequence $<data>#<checksum> and store <data> in the array buffer
+   returned. */
+static void getpacket (char *buffer);
+
+/* Send $<data>#<checksum> from the <data> in the array buffer. */
+static void putpacket (char *buffer);
+
+/* Build and send a response packet in order to inform the host the
+   stub is stopped. */
+static void stub_is_stopped (int sigval);
+
+/* All expected commands are sent from remote.c. Send a response according
+   to the description in remote.c. */
+static void handle_exception (int sigval);
+
+/* Performs a complete re-start from scratch. ETRAX specific. */
+static void kill_restart (void);
+
+/******************** Prototypes for global functions. ***********************/
+
+/* The string str is prepended with the GDB printout token and sent. */
+void putDebugString (const unsigned char *str, int length); /* used by etrax100ser.c */
+
+/* The hook for both static (compiled) and dynamic breakpoints set by GDB.
+   ETRAX 100 specific. */
+void handle_breakpoint (void);                          /* used by irq.c */
+
+/* The hook for an interrupt generated by GDB. ETRAX 100 specific. */
+void handle_interrupt (void);                           /* used by irq.c */
+
+/* A static breakpoint to be used at startup. */
+void breakpoint (void);                                 /* called by init/main.c */
+
+/* From osys_int.c, executing_task contains the number of the current
+   executing task in osys. Does not know of object-oriented threads. */
+extern unsigned char executing_task;
+
+/* The number of characters used for a 64 bit thread identifier. */
+#define HEXCHARS_IN_THREAD_ID 16
+
+/* Avoid warning as the internal_stack is not used in the C-code. */
+#define USEDVAR(name)    { if (name) { ; } }
+#define USEDFUN(name) { void (*pf)(void) = (void *)name; USEDVAR(pf) }
+
+/********************************** Packet I/O ******************************/
+/* BUFMAX defines the maximum number of characters in
+   inbound/outbound buffers */
+#define BUFMAX 512
+
+/* Run-length encoding maximum length. Send 64 at most. */
+#define RUNLENMAX 64
+
+/* Definition of all valid hexadecimal characters */
+static const char hexchars[] = "0123456789abcdef";
+
+/* The inbound/outbound buffers used in packet I/O */
+static char remcomInBuffer[BUFMAX];
+static char remcomOutBuffer[BUFMAX];
+
+/* Error and warning messages. */
+enum error_type
+{
+	SUCCESS, E01, E02, E03, E04, E05, E06, E07
+};
+static char *error_message[] =
+{
+	"",
+	"E01 Set current or general thread - H[c,g] - internal error.",
+	"E02 Change register content - P - cannot change read-only register.",
+	"E03 Thread is not alive.", /* T, not used. */
+	"E04 The command is not supported - [s,C,S,!,R,d,r] - internal error.",
+	"E05 Change register content - P - the register is not implemented..",
+	"E06 Change memory content - M - internal error.",
+	"E07 Change register content - P - the register is not stored on the stack"
+};
+/********************************* Register image ****************************/
+/* Use the order of registers as defined in "AXIS ETRAX CRIS Programmer's
+   Reference", p. 1-1, with the additional register definitions of the
+   ETRAX 100LX in cris-opc.h.
+   There are 16 general 32-bit registers, R0-R15, where R14 is the stack
+   pointer, SP, and R15 is the program counter, PC.
+   There are 16 special registers, P0-P15, where three of the unimplemented
+   registers, P0, P4 and P8, are reserved as zero-registers. A read from
+   any of these registers returns zero and a write has no effect. */
+enum register_name
+{
+	R0,  R1,   R2,  R3,
+	R4,  R5,   R6,  R7,
+	R8,  R9,   R10, R11,
+	R12, R13,  SP,  PC,
+	P0,  VR,   P2,  P3,
+	P4,  CCR,  P6,  MOF,
+	P8,  IBR,  IRP, SRP,
+	BAR, DCCR, BRP, USP
+};
+
+/* The register sizes of the registers in register_name. An unimplemented register
+   is designated by size 0 in this array. */
+static int register_size[] =
+{
+	4, 4, 4, 4,
+	4, 4, 4, 4,
+	4, 4, 4, 4,
+	4, 4, 4, 4,
+	1, 1, 0, 0,
+	2, 2, 0, 4,
+	4, 4, 4, 4,
+	4, 4, 4, 4
+};
+
+/* Contains the register image of the executing thread in the assembler
+   part of the code in order to avoid horrible addressing modes. */
+static registers reg;
+
+/* FIXME: Should this be used? Delete otherwise. */
+/* Contains the assumed consistency state of the register image. Uses the
+   enum error_type for state information. */
+static int consistency_status = SUCCESS;
+
+/********************************** Handle exceptions ************************/
+/* The variable reg contains the register image associated with the
+   current_thread_c variable. It is a complete register image created at
+   entry. The reg_g contains a register image of a task where the general
+   registers are taken from the stack and all special registers are taken
+   from the executing task. It is associated with current_thread_g and used
+   in order to provide access mainly for 'g', 'G' and 'P'.
+*/
+
+/* Need two task id pointers in order to handle Hct and Hgt commands. */
+static int current_thread_c = 0;
+static int current_thread_g = 0;
+
+/* Need two register images in order to handle Hct and Hgt commands. The
+   variable reg_g is in addition to reg above. */
+static registers reg_g;
+
+/********************************** Breakpoint *******************************/
+/* Use an internal stack in the breakpoint and interrupt response routines */
+#define INTERNAL_STACK_SIZE 1024
+static char internal_stack[INTERNAL_STACK_SIZE];
+
+/* Due to the breakpoint return pointer, a state variable is needed to keep
+   track of whether it is a static (compiled) or dynamic (gdb-invoked)
+   breakpoint to be handled. A static breakpoint uses the content of register
+   BRP as it is whereas a dynamic breakpoint requires subtraction with 2
+   in order to execute the instruction. The first breakpoint is static. */
+static unsigned char is_dyn_brkp = 0;
+
+/********************************* String library ****************************/
+/* Single-step over library functions creates trap loops. */
+
+/* Copy char s2[] to s1[]. */
+static char*
+gdb_cris_strcpy (char *s1, const char *s2)
+{
+	char *s = s1;
+	
+	for (s = s1; (*s++ = *s2++) != '\0'; )
+		;
+	return (s1);
+}
+
+/* Find length of s[]. */
+static int
+gdb_cris_strlen (const char *s)
+{
+	const char *sc;
+	
+	for (sc = s; *sc != '\0'; sc++)
+		;
+	return (sc - s);
+}
+
+/* Find first occurrence of c in s[n]. */
+static void*
+gdb_cris_memchr (const void *s, int c, int n)
+{
+	const unsigned char uc = c;
+	const unsigned char *su;
+	
+	for (su = s; 0 < n; ++su, --n)
+		if (*su == uc)
+			return ((void *)su);
+	return (NULL);
+}
+/******************************* Standard library ****************************/
+/* Single-step over library functions creates trap loops. */
+/* Convert string to long. */
+static int
+gdb_cris_strtol (const char *s, char **endptr, int base)
+{
+	char *s1;
+	char *sd;
+	int x = 0;
+	
+	for (s1 = (char*)s; (sd = gdb_cris_memchr(hexchars, *s1, base)) != NULL; ++s1)
+		x = x * base + (sd - hexchars);
+        
+        if (endptr)
+        {
+                /* Unconverted suffix is stored in endptr unless endptr is NULL. */
+                *endptr = s1;
+        }
+        
+	return x;
+}
+
+int
+double_this(int x)
+{
+        return 2 * x;
+}
+
+/********************************* Register image ****************************/
+/* Copy the content of a register image into another. The size n is
+   the size of the register image. Due to struct assignment generation of
+   memcpy in libc. */
+static void
+copy_registers (registers *dptr, registers *sptr, int n)
+{
+	unsigned char *dreg;
+	unsigned char *sreg;
+	
+	for (dreg = (unsigned char*)dptr, sreg = (unsigned char*)sptr; n > 0; n--)
+		*dreg++ = *sreg++;
+}
+
+#ifdef PROCESS_SUPPORT
+/* Copy the stored registers from the stack. Put the register contents
+   of thread thread_id in the struct reg. */
+static void
+copy_registers_from_stack (int thread_id, registers *regptr)
+{
+	int j;
+	stack_registers *s = (stack_registers *)stack_list[thread_id];
+	unsigned int *d = (unsigned int *)regptr;
+	
+	for (j = 13; j >= 0; j--)
+		*d++ = s->r[j];
+	regptr->sp = (unsigned int)stack_list[thread_id];
+	regptr->pc = s->pc;
+	regptr->dccr = s->dccr;
+	regptr->srp = s->srp;
+}
+
+/* Copy the registers to the stack. Put the register contents of thread
+   thread_id from struct reg to the stack. */
+static void
+copy_registers_to_stack (int thread_id, registers *regptr)
+{
+	int i;
+	stack_registers *d = (stack_registers *)stack_list[thread_id];
+	unsigned int *s = (unsigned int *)regptr;
+	
+	for (i = 0; i < 14; i++) {
+		d->r[i] = *s++;
+	}
+	d->pc = regptr->pc;
+	d->dccr = regptr->dccr;
+	d->srp = regptr->srp;
+}
+#endif
+
+/* Write a value to a specified register in the register image of the current
+   thread. Returns status code SUCCESS, E02 or E05. */
+static int
+write_register (int regno, char *val)
+{
+	int status = SUCCESS;
+	registers *current_reg = &reg;
+
+        if (regno >= R0 && regno <= PC) {
+		/* 32-bit register with simple offset. */
+		hex2mem ((unsigned char *)current_reg + regno * sizeof(unsigned int),
+			 val, sizeof(unsigned int));
+	}
+        else if (regno == P0 || regno == VR || regno == P4 || regno == P8) {
+		/* Do not support read-only registers. */
+		status = E02;
+	}
+        else if (regno == CCR) {
+		/* 16 bit register with complex offset. (P4 is read-only, P6 is not implemented, 
+                   and P7 (MOF) is 32 bits in ETRAX 100LX. */
+		hex2mem ((unsigned char *)&(current_reg->ccr) + (regno-CCR) * sizeof(unsigned short),
+			 val, sizeof(unsigned short));
+	}
+	else if (regno >= MOF && regno <= USP) {
+		/* 32 bit register with complex offset.  (P8 has been taken care of.) */
+		hex2mem ((unsigned char *)&(current_reg->ibr) + (regno-IBR) * sizeof(unsigned int),
+			 val, sizeof(unsigned int));
+	} 
+        else {
+		/* Do not support nonexisting or unimplemented registers (P2, P3, and P6). */
+		status = E05;
+	}
+	return status;
+}
+
+#ifdef PROCESS_SUPPORT
+/* Write a value to a specified register in the stack of a thread other
+   than the current thread. Returns status code SUCCESS or E07. */
+static int
+write_stack_register (int thread_id, int regno, char *valptr)
+{
+	int status = SUCCESS;
+	stack_registers *d = (stack_registers *)stack_list[thread_id];
+	unsigned int val;
+	
+	hex2mem ((unsigned char *)&val, valptr, sizeof(unsigned int));
+	if (regno >= R0 && regno < SP) {
+		d->r[regno] = val;
+	}
+	else if (regno == SP) {
+		stack_list[thread_id] = val;
+	}
+	else if (regno == PC) {
+		d->pc = val;
+	}
+	else if (regno == SRP) {
+		d->srp = val;
+	}
+	else if (regno == DCCR) {
+		d->dccr = val;
+	}
+	else {
+		/* Do not support registers in the current thread. */
+		status = E07;
+	}
+	return status;
+}
+#endif
+
+/* Read a value from a specified register in the register image. Returns the
+   value in the register or -1 for non-implemented registers.
+   Should check consistency_status after a call which may be E05 after changes
+   in the implementation. */
+static int
+read_register (char regno, unsigned int *valptr)
+{
+	registers *current_reg = &reg;
+
+	if (regno >= R0 && regno <= PC) {
+		/* 32-bit register with simple offset. */
+		*valptr = *(unsigned int *)((char *)current_reg + regno * sizeof(unsigned int));
+                return SUCCESS;
+	}
+	else if (regno == P0 || regno == VR) {
+		/* 8 bit register with complex offset. */
+		*valptr = (unsigned int)(*(unsigned char *)
+                                         ((char *)&(current_reg->p0) + (regno-P0) * sizeof(char)));
+                return SUCCESS;
+	}
+	else if (regno == P4 || regno == CCR) {
+		/* 16 bit register with complex offset. */
+		*valptr = (unsigned int)(*(unsigned short *)
+                                         ((char *)&(current_reg->p4) + (regno-P4) * sizeof(unsigned short)));
+                return SUCCESS;
+	}
+	else if (regno >= MOF && regno <= USP) {
+		/* 32 bit register with complex offset. */
+		*valptr = *(unsigned int *)((char *)&(current_reg->p8)
+                                            + (regno-P8) * sizeof(unsigned int));
+                return SUCCESS;
+	}
+	else {
+		/* Do not support nonexisting or unimplemented registers (P2, P3, and P6). */
+		consistency_status = E05;
+		return E05;
+	}
+}
+
+/********************************** Packet I/O ******************************/
+/* Returns the character equivalent of a nibble, bit 7, 6, 5, and 4 of a byte,
+   represented by int x. */
+static inline char
+highhex(int x)
+{
+	return hexchars[(x >> 4) & 0xf];
+}
+
+/* Returns the character equivalent of a nibble, bit 3, 2, 1, and 0 of a byte,
+   represented by int x. */
+static inline char
+lowhex(int x)
+{
+	return hexchars[x & 0xf];
+}
+
+/* Returns the integer equivalent of a hexadecimal character. */
+static int
+hex (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);
+}
+
+/* Convert the memory, pointed to by mem into hexadecimal representation.
+   Put the result in buf, and return a pointer to the last character
+   in buf (null). */
+
+static int do_printk = 0;
+
+static char *
+mem2hex(char *buf, unsigned char *mem, int count)
+{
+	int i;
+	int ch;
+        
+        if (mem == NULL) {
+                /* Bogus read from m0. FIXME: What constitutes a valid address? */
+                for (i = 0; i < count; i++) {
+                        *buf++ = '0';
+                        *buf++ = '0';
+                }
+        } else {
+                /* Valid mem address. */
+                for (i = 0; i < count; i++) {
+                        ch = *mem++;
+                        *buf++ = highhex (ch);
+                        *buf++ = lowhex (ch);
+                }
+        }
+        
+        /* Terminate properly. */
+	*buf = '\0';
+	return (buf);
+}
+
+/* Convert the array, in hexadecimal representation, pointed to by buf into
+   binary representation. Put the result in mem, and return a pointer to
+   the character after the last byte written. */
+static unsigned char*
+hex2mem (unsigned char *mem, char *buf, int count)
+{
+	int i;
+	unsigned char ch;
+	for (i = 0; i < count; i++) {
+		ch = hex (*buf++) << 4;
+		ch = ch + hex (*buf++);
+		*mem++ = ch;
+	}
+	return (mem);
+}
+
+/* Put the content of the array, in binary representation, pointed to by buf
+   into memory pointed to by mem, and return a pointer to the character after
+   the last byte written.
+   Gdb will escape $, #, and the escape char (0x7d). */
+static unsigned char*
+bin2mem (unsigned char *mem, unsigned char *buf, int count)
+{
+	int i;
+	unsigned char *next;
+	for (i = 0; i < count; i++) {
+		/* Check for any escaped characters. Be paranoid and
+		   only unescape chars that should be escaped. */
+		if (*buf == 0x7d) {
+			next = buf + 1;
+			if (*next == 0x3 || *next == 0x4 || *next == 0x5D) /* #, $, ESC */
+				{
+					buf++;
+					*buf += 0x20;
+				}
+		}
+		*mem++ = *buf++;
+	}
+	return (mem);
+}
+
+/* Await the sequence $<data>#<checksum> and store <data> in the array buffer
+   returned. */
+static void
+getpacket (char *buffer)
+{
+	unsigned char checksum;
+	unsigned char xmitcsum;
+	int i;
+	int count;
+	char ch;
+	do {
+		while ((ch = getDebugChar ()) != '$')
+			/* Wait for the start character $ and ignore all other characters */;
+		checksum = 0;
+		xmitcsum = -1;
+		count = 0;
+		/* Read until a # or the end of the buffer is reached */
+		while (count < BUFMAX) {
+			ch = getDebugChar ();
+			if (ch == '#')
+				break;
+			checksum = checksum + ch;
+			buffer[count] = ch;
+			count = count + 1;
+		}
+		buffer[count] = '\0';
+		
+		if (ch == '#') {
+			xmitcsum = hex (getDebugChar ()) << 4;
+			xmitcsum += hex (getDebugChar ());
+			if (checksum != xmitcsum) {
+				/* Wrong checksum */
+				putDebugChar ('-');
+			}
+			else {
+				/* Correct checksum */
+				putDebugChar ('+');
+				/* If sequence characters are received, reply with them */
+				if (buffer[2] == ':') {
+					putDebugChar (buffer[0]);
+					putDebugChar (buffer[1]);
+					/* Remove the sequence characters from the buffer */
+					count = gdb_cris_strlen (buffer);
+					for (i = 3; i <= count; i++)
+						buffer[i - 3] = buffer[i];
+				}
+			}
+		}
+	} while (checksum != xmitcsum);
+}
+
+/* Send $<data>#<checksum> from the <data> in the array buffer. */
+
+static void
+putpacket(char *buffer)
+{
+	int checksum;
+	int runlen;
+	int encode;
+	
+	do {
+		char *src = buffer;
+		putDebugChar ('$');
+		checksum = 0;
+		while (*src) {
+			/* Do run length encoding */
+			putDebugChar (*src);
+			checksum += *src;
+			runlen = 0;
+			while (runlen < RUNLENMAX && *src == src[runlen]) {
+				runlen++;
+			}
+			if (runlen > 3) {
+				/* Got a useful amount */
+				putDebugChar ('*');
+				checksum += '*';
+				encode = runlen + ' ' - 4;
+				putDebugChar (encode);
+				checksum += encode;
+				src += runlen;
+			}
+			else {
+				src++;
+			}
+		}
+		putDebugChar ('#');
+		putDebugChar (highhex (checksum));
+		putDebugChar (lowhex (checksum));
+	} while(kgdb_started && (getDebugChar() != '+'));
+}
+
+/* The string str is prepended with the GDB printout token and sent. Required
+   in traditional implementations. */
+void
+putDebugString (const unsigned char *str, int length)
+{
+        remcomOutBuffer[0] = 'O';
+        mem2hex(&remcomOutBuffer[1], (unsigned char *)str, length);
+        putpacket(remcomOutBuffer);
+}
+
+/********************************** Handle exceptions ************************/
+/* Build and send a response packet in order to inform the host the
+   stub is stopped. TAAn...:r...;n...:r...;n...:r...;
+                    AA = signal number
+                    n... = register number (hex)
+                    r... = register contents
+                    n... = `thread'
+                    r... = thread process ID.  This is a hex integer.
+                    n... = other string not starting with valid hex digit.
+                    gdb should ignore this n,r pair and go on to the next.
+                    This way we can extend the protocol. */
+static void
+stub_is_stopped(int sigval)
+{
+	char *ptr = remcomOutBuffer;
+	int regno;
+
+	unsigned int reg_cont;
+	int status;
+        
+	/* Send trap type (converted to signal) */
+
+	*ptr++ = 'T';	
+	*ptr++ = highhex (sigval);
+	*ptr++ = lowhex (sigval);
+
+	/* Send register contents. We probably only need to send the
+	 * PC, frame pointer and stack pointer here. Other registers will be
+	 * explicitely asked for. But for now, send all. 
+	 */
+	
+	for (regno = R0; regno <= USP; regno++) {
+		/* Store n...:r...; for the registers in the buffer. */
+
+                status = read_register (regno, &reg_cont);
+                
+		if (status == SUCCESS) {
+                        
+                        *ptr++ = highhex (regno);
+                        *ptr++ = lowhex (regno);
+                        *ptr++ = ':';
+
+                        ptr = mem2hex(ptr, (unsigned char *)&reg_cont,
+                                      register_size[regno]);
+                        *ptr++ = ';';
+                }
+                
+	}
+
+#ifdef PROCESS_SUPPORT
+	/* Store the registers of the executing thread. Assume that both step,
+	   continue, and register content requests are with respect to this
+	   thread. The executing task is from the operating system scheduler. */
+
+	current_thread_c = executing_task;
+	current_thread_g = executing_task;
+
+	/* A struct assignment translates into a libc memcpy call. Avoid
+	   all libc functions in order to prevent recursive break points. */
+	copy_registers (&reg_g, &reg, sizeof(registers));
+
+	/* Store thread:r...; with the executing task TID. */
+	gdb_cris_strcpy (&remcomOutBuffer[pos], "thread:");
+	pos += gdb_cris_strlen ("thread:");
+	remcomOutBuffer[pos++] = highhex (executing_task);
+	remcomOutBuffer[pos++] = lowhex (executing_task);
+	gdb_cris_strcpy (&remcomOutBuffer[pos], ";");
+#endif
+
+	/* null-terminate and send it off */
+
+	*ptr = 0;
+
+	putpacket (remcomOutBuffer);
+}
+
+/* All expected commands are sent from remote.c. Send a response according
+   to the description in remote.c. */
+static void
+handle_exception (int sigval)
+{
+	/* Avoid warning of not used. */
+
+	USEDFUN(handle_exception);
+	USEDVAR(internal_stack[0]);
+
+	/* Send response. */
+
+	stub_is_stopped (sigval);
+
+	for (;;) {
+		remcomOutBuffer[0] = '\0';
+		getpacket (remcomInBuffer);
+		switch (remcomInBuffer[0]) {
+			case 'g':
+				/* Read registers: g
+				   Success: Each byte of register data is described by two hex digits.
+				   Registers are in the internal order for GDB, and the bytes
+				   in a register  are in the same order the machine uses.
+				   Failure: void. */
+				
+				{
+#ifdef PROCESS_SUPPORT
+					/* Use the special register content in the executing thread. */
+					copy_registers (&reg_g, &reg, sizeof(registers));
+					/* Replace the content available on the stack. */
+					if (current_thread_g != executing_task) {
+						copy_registers_from_stack (current_thread_g, &reg_g);
+					}
+					mem2hex ((unsigned char *)remcomOutBuffer, (unsigned char *)&reg_g, sizeof(registers));
+#else
+					mem2hex(remcomOutBuffer, (char *)&reg, sizeof(registers));
+#endif
+				}
+				break;
+				
+			case 'G':
+				/* Write registers. GXX..XX
+				   Each byte of register data  is described by two hex digits.
+				   Success: OK
+				   Failure: void. */
+#ifdef PROCESS_SUPPORT
+				hex2mem ((unsigned char *)&reg_g, &remcomInBuffer[1], sizeof(registers));
+				if (current_thread_g == executing_task) {
+					copy_registers (&reg, &reg_g, sizeof(registers));
+				}
+				else {
+					copy_registers_to_stack(current_thread_g, &reg_g);
+				}
+#else
+				hex2mem((char *)&reg, &remcomInBuffer[1], sizeof(registers));
+#endif
+				gdb_cris_strcpy (remcomOutBuffer, "OK");
+				break;
+				
+			case 'P':
+				/* Write register. Pn...=r...
+				   Write register n..., hex value without 0x, with value r...,
+				   which contains a hex value without 0x and two hex digits
+				   for each byte in the register (target byte order). P1f=11223344 means
+				   set register 31 to 44332211.
+				   Success: OK
+				   Failure: E02, E05 */
+				{
+					char *suffix;
+					int regno = gdb_cris_strtol (&remcomInBuffer[1], &suffix, 16);
+					int status;
+#ifdef PROCESS_SUPPORT
+					if (current_thread_g != executing_task)
+						status = write_stack_register (current_thread_g, regno, suffix+1);
+					else
+#endif
+						status = write_register (regno, suffix+1);
+
+					switch (status) {
+						case E02:
+							/* Do not support read-only registers. */
+							gdb_cris_strcpy (remcomOutBuffer, error_message[E02]);
+							break;
+						case E05:
+							/* Do not support non-existing registers. */
+							gdb_cris_strcpy (remcomOutBuffer, error_message[E05]);
+							break;
+						case E07:
+							/* Do not support non-existing registers on the stack. */
+							gdb_cris_strcpy (remcomOutBuffer, error_message[E07]);
+							break;
+						default:
+							/* Valid register number. */
+							gdb_cris_strcpy (remcomOutBuffer, "OK");
+							break;
+					}
+				}
+				break;
+				
+			case 'm':
+				/* Read from memory. mAA..AA,LLLL
+				   AA..AA is the address and LLLL is the length.
+				   Success: XX..XX is the memory content.  Can be fewer bytes than
+				   requested if only part of the data may be read. m6000120a,6c means
+				   retrieve 108 byte from base address 6000120a.
+				   Failure: void. */
+				{
+                                        char *suffix;
+					unsigned char *addr = (unsigned char *)gdb_cris_strtol(&remcomInBuffer[1],
+                                                                                               &suffix, 16);                                        int length = gdb_cris_strtol(suffix+1, 0, 16);
+                                        
+                                        mem2hex(remcomOutBuffer, addr, length);
+                                }
+				break;
+				
+			case 'X':
+				/* Write to memory. XAA..AA,LLLL:XX..XX
+				   AA..AA is the start address,  LLLL is the number of bytes, and
+				   XX..XX is the binary data.
+				   Success: OK
+				   Failure: void. */
+			case 'M':
+				/* Write to memory. MAA..AA,LLLL:XX..XX
+				   AA..AA is the start address,  LLLL is the number of bytes, and
+				   XX..XX is the hexadecimal data.
+				   Success: OK
+				   Failure: void. */
+				{
+					char *lenptr;
+					char *dataptr;
+					unsigned char *addr = (unsigned char *)gdb_cris_strtol(&remcomInBuffer[1],
+										      &lenptr, 16);
+					int length = gdb_cris_strtol(lenptr+1, &dataptr, 16);
+					if (*lenptr == ',' && *dataptr == ':') {
+						if (remcomInBuffer[0] == 'M') {
+							hex2mem(addr, dataptr + 1, length);
+						}
+						else /* X */ {
+							bin2mem(addr, dataptr + 1, length);
+						}
+						gdb_cris_strcpy (remcomOutBuffer, "OK");
+					}
+					else {
+						gdb_cris_strcpy (remcomOutBuffer, error_message[E06]);
+					}
+				}
+				break;
+				
+			case 'c':
+				/* Continue execution. cAA..AA
+				   AA..AA is the address where execution is resumed. If AA..AA is
+				   omitted, resume at the present address.
+				   Success: return to the executing thread.
+				   Failure: will never know. */
+				if (remcomInBuffer[1] != '\0') {
+					reg.pc = gdb_cris_strtol (&remcomInBuffer[1], 0, 16);
+				}
+				enableDebugIRQ();
+				return;
+				
+			case 's':
+				/* Step. sAA..AA
+				   AA..AA is the address where execution is resumed. If AA..AA is
+				   omitted, resume at the present address. Success: return to the
+				   executing thread. Failure: will never know.
+				   
+				   Should never be invoked. The single-step is implemented on
+				   the host side. If ever invoked, it is an internal error E04. */
+				gdb_cris_strcpy (remcomOutBuffer, error_message[E04]);
+				putpacket (remcomOutBuffer);
+				return;
+				
+			case '?':
+				/* The last signal which caused a stop. ?
+				   Success: SAA, where AA is the signal number.
+				   Failure: void. */
+				remcomOutBuffer[0] = 'S';
+				remcomOutBuffer[1] = highhex (sigval);
+				remcomOutBuffer[2] = lowhex (sigval);
+				remcomOutBuffer[3] = 0;
+				break;
+				
+			case 'D':
+				/* Detach from host. D
+				   Success: OK, and return to the executing thread.
+				   Failure: will never know */
+				putpacket ("OK");
+				return;
+				
+			case 'k':
+			case 'r':
+				/* kill request or reset request.
+				   Success: restart of target.
+				   Failure: will never know. */
+				kill_restart ();
+				break;
+				
+			case 'C':
+			case 'S':
+			case '!':
+			case 'R':
+			case 'd':
+				/* Continue with signal sig. Csig;AA..AA
+				   Step with signal sig. Ssig;AA..AA
+				   Use the extended remote protocol. !
+				   Restart the target system. R0
+				   Toggle debug flag. d
+				   Search backwards. tAA:PP,MM
+				   Not supported: E04 */
+				gdb_cris_strcpy (remcomOutBuffer, error_message[E04]);
+				break;
+#ifdef PROCESS_SUPPORT
+
+			case 'T':
+				/* Thread alive. TXX
+				   Is thread XX alive?
+				   Success: OK, thread XX is alive.
+				   Failure: E03, thread XX is dead. */
+				{
+					int thread_id = (int)gdb_cris_strtol (&remcomInBuffer[1], 0, 16);
+					/* Cannot tell whether it is alive or not. */
+					if (thread_id >= 0 && thread_id < number_of_tasks)
+						gdb_cris_strcpy (remcomOutBuffer, "OK");
+				}
+				break;
+								
+			case 'H':
+				/* Set thread for subsequent operations: Hct
+				   c = 'c' for thread used in step and continue;
+				   t can be -1 for all threads.
+				   c = 'g' for thread used in other  operations.
+				   t = 0 means pick any thread.
+				   Success: OK
+				   Failure: E01 */
+				{
+					int thread_id = gdb_cris_strtol (&remcomInBuffer[2], 0, 16);
+					if (remcomInBuffer[1] == 'c') {
+						/* c = 'c' for thread used in step and continue */
+						/* Do not change current_thread_c here. It would create a mess in
+						   the scheduler. */
+						gdb_cris_strcpy (remcomOutBuffer, "OK");
+					}
+					else if (remcomInBuffer[1] == 'g') {
+						/* c = 'g' for thread used in other  operations.
+						   t = 0 means pick any thread. Impossible since the scheduler does
+						   not allow that. */
+						if (thread_id >= 0 && thread_id < number_of_tasks) {
+							current_thread_g = thread_id;
+							gdb_cris_strcpy (remcomOutBuffer, "OK");
+						}
+						else {
+							/* Not expected - send an error message. */
+							gdb_cris_strcpy (remcomOutBuffer, error_message[E01]);
+						}
+					}
+					else {
+						/* Not expected - send an error message. */
+						gdb_cris_strcpy (remcomOutBuffer, error_message[E01]);
+					}
+				}
+				break;
+				
+			case 'q':
+			case 'Q':
+				/* Query of general interest. qXXXX
+				   Set general value XXXX. QXXXX=yyyy */
+				{
+					int pos;
+					int nextpos;
+					int thread_id;
+					
+					switch (remcomInBuffer[1]) {
+						case 'C':
+							/* Identify the remote current thread. */
+							gdb_cris_strcpy (&remcomOutBuffer[0], "QC");
+							remcomOutBuffer[2] = highhex (current_thread_c);
+							remcomOutBuffer[3] = lowhex (current_thread_c);
+							remcomOutBuffer[4] = '\0';
+							break;
+						case 'L':
+							gdb_cris_strcpy (&remcomOutBuffer[0], "QM");
+							/* Reply with number of threads. */
+							if (os_is_started()) {
+								remcomOutBuffer[2] = highhex (number_of_tasks);
+								remcomOutBuffer[3] = lowhex (number_of_tasks);
+							}
+							else {
+								remcomOutBuffer[2] = highhex (0);
+								remcomOutBuffer[3] = lowhex (1);
+							}
+							/* Done with the reply. */
+							remcomOutBuffer[4] = lowhex (1);
+							pos = 5;
+							/* Expects the argument thread id. */
+							for (; pos < (5 + HEXCHARS_IN_THREAD_ID); pos++)
+								remcomOutBuffer[pos] = remcomInBuffer[pos];
+							/* Reply with the thread identifiers. */
+							if (os_is_started()) {
+								/* Store the thread identifiers of all tasks. */
+								for (thread_id = 0; thread_id < number_of_tasks; thread_id++) {
+									nextpos = pos + HEXCHARS_IN_THREAD_ID - 1;
+									for (; pos < nextpos; pos ++)
+										remcomOutBuffer[pos] = lowhex (0);
+									remcomOutBuffer[pos++] = lowhex (thread_id);
+								}
+							}
+							else {
+								/* Store the thread identifier of the boot task. */
+								nextpos = pos + HEXCHARS_IN_THREAD_ID - 1;
+								for (; pos < nextpos; pos ++)
+									remcomOutBuffer[pos] = lowhex (0);
+								remcomOutBuffer[pos++] = lowhex (current_thread_c);
+							}
+							remcomOutBuffer[pos] = '\0';
+							break;
+						default:
+							/* Not supported: "" */
+							/* Request information about section offsets: qOffsets. */
+							remcomOutBuffer[0] = 0;
+							break;
+					}
+				}
+				break;
+#endif /* PROCESS_SUPPORT */
+				
+			default:
+				/* The stub should ignore other request and send an empty
+				   response ($#<checksum>). This way we can extend the protocol and GDB
+				   can tell whether the stub it is talking to uses the old or the new. */
+				remcomOutBuffer[0] = 0;
+				break;
+		}
+		putpacket(remcomOutBuffer);
+	}
+}
+
+/* The jump is to the address 0x00000002. Performs a complete re-start
+   from scratch. */
+static void
+kill_restart ()
+{
+	__asm__ volatile ("jump 2");
+}
+
+/********************************** Breakpoint *******************************/
+/* The hook for both a static (compiled) and a dynamic breakpoint set by GDB.
+   An internal stack is used by the stub. The register image of the caller is
+   stored in the structure register_image.
+   Interactive communication with the host is handled by handle_exception and
+   finally the register image is restored. */
+
+void kgdb_handle_breakpoint(void);
+
+asm ("
+  .global kgdb_handle_breakpoint
+kgdb_handle_breakpoint:
+;;
+;; Response to the break-instruction
+;;
+;; Create a register image of the caller
+;;
+  move     $dccr,[reg+0x5E] ; Save the flags in DCCR before disable interrupts
+  di                        ; Disable interrupts
+  move.d   $r0,[reg]        ; Save R0
+  move.d   $r1,[reg+0x04]   ; Save R1
+  move.d   $r2,[reg+0x08]   ; Save R2
+  move.d   $r3,[reg+0x0C]   ; Save R3
+  move.d   $r4,[reg+0x10]   ; Save R4
+  move.d   $r5,[reg+0x14]   ; Save R5
+  move.d   $r6,[reg+0x18]   ; Save R6
+  move.d   $r7,[reg+0x1C]   ; Save R7
+  move.d   $r8,[reg+0x20]   ; Save R8
+  move.d   $r9,[reg+0x24]   ; Save R9
+  move.d   $r10,[reg+0x28]  ; Save R10
+  move.d   $r11,[reg+0x2C]  ; Save R11
+  move.d   $r12,[reg+0x30]  ; Save R12
+  move.d   $r13,[reg+0x34]  ; Save R13
+  move.d   $sp,[reg+0x38]   ; Save SP (R14)
+;; Due to the old assembler-versions BRP might not be recognized
+  .word 0xE670              ; move brp,$r0
+  subq     2,$r0             ; Set to address of previous instruction.
+  move.d   $r0,[reg+0x3c]   ; Save the address in PC (R15)
+  clear.b  [reg+0x40]      ; Clear P0
+  move     $vr,[reg+0x41]   ; Save special register P1
+  clear.w  [reg+0x42]      ; Clear P4
+  move     $ccr,[reg+0x44]  ; Save special register CCR
+  move     $mof,[reg+0x46]  ; P7
+  clear.d  [reg+0x4A]      ; Clear P8
+  move     $ibr,[reg+0x4E]  ; P9,
+  move     $irp,[reg+0x52]  ; P10,
+  move     $srp,[reg+0x56]  ; P11,
+  move     $dtp0,[reg+0x5A] ; P12, register BAR, assembler might not know BAR
+                            ; P13, register DCCR already saved
+;; Due to the old assembler-versions BRP might not be recognized
+  .word 0xE670              ; move brp,r0
+;; Static (compiled) breakpoints must return to the next instruction in order
+;; to avoid infinite loops. Dynamic (gdb-invoked) must restore the instruction
+;; in order to execute it when execution is continued.
+  test.b   [is_dyn_brkp]    ; Is this a dynamic breakpoint?
+  beq      is_static         ; No, a static breakpoint
+  nop
+  subq     2,$r0              ; rerun the instruction the break replaced
+is_static:
+  moveq    1,$r1
+  move.b   $r1,[is_dyn_brkp] ; Set the state variable to dynamic breakpoint
+  move.d   $r0,[reg+0x62]    ; Save the return address in BRP
+  move     $usp,[reg+0x66]   ; USP
+;;
+;; Handle the communication
+;;
+  move.d   internal_stack+1020,$sp ; Use the internal stack which grows upward
+  moveq    5,$r10                   ; SIGTRAP
+  jsr      handle_exception       ; Interactive routine
+;;
+;; Return to the caller
+;;
+   move.d  [reg],$r0         ; Restore R0
+   move.d  [reg+0x04],$r1    ; Restore R1
+   move.d  [reg+0x08],$r2    ; Restore R2
+   move.d  [reg+0x0C],$r3    ; Restore R3
+   move.d  [reg+0x10],$r4    ; Restore R4
+   move.d  [reg+0x14],$r5    ; Restore R5
+   move.d  [reg+0x18],$r6    ; Restore R6
+   move.d  [reg+0x1C],$r7    ; Restore R7
+   move.d  [reg+0x20],$r8    ; Restore R8
+   move.d  [reg+0x24],$r9    ; Restore R9
+   move.d  [reg+0x28],$r10   ; Restore R10
+   move.d  [reg+0x2C],$r11   ; Restore R11
+   move.d  [reg+0x30],$r12   ; Restore R12
+   move.d  [reg+0x34],$r13   ; Restore R13
+;;
+;; FIXME: Which registers should be restored?
+;;
+   move.d  [reg+0x38],$sp    ; Restore SP (R14)
+   move    [reg+0x56],$srp   ; Restore the subroutine return pointer.
+   move    [reg+0x5E],$dccr  ; Restore DCCR
+   move    [reg+0x66],$usp   ; Restore USP
+   jump    [reg+0x62]       ; A jump to the content in register BRP works.
+   nop                       ;
+");
+
+/* The hook for an interrupt generated by GDB. An internal stack is used
+   by the stub. The register image of the caller is stored in the structure
+   register_image. Interactive communication with the host is handled by
+   handle_exception and finally the register image is restored. Due to the
+   old assembler which does not recognise the break instruction and the
+   breakpoint return pointer hex-code is used. */
+
+void kgdb_handle_serial(void);
+
+asm ("
+  .global kgdb_handle_serial
+kgdb_handle_serial:
+;;
+;; Response to a serial interrupt
+;;
+
+  move     $dccr,[reg+0x5E] ; Save the flags in DCCR
+  di                        ; Disable interrupts
+  move.d   $r0,[reg]        ; Save R0
+  move.d   $r1,[reg+0x04]   ; Save R1
+  move.d   $r2,[reg+0x08]   ; Save R2
+  move.d   $r3,[reg+0x0C]   ; Save R3
+  move.d   $r4,[reg+0x10]   ; Save R4
+  move.d   $r5,[reg+0x14]   ; Save R5
+  move.d   $r6,[reg+0x18]   ; Save R6
+  move.d   $r7,[reg+0x1C]   ; Save R7
+  move.d   $r8,[reg+0x20]   ; Save R8
+  move.d   $r9,[reg+0x24]   ; Save R9
+  move.d   $r10,[reg+0x28]  ; Save R10
+  move.d   $r11,[reg+0x2C]  ; Save R11
+  move.d   $r12,[reg+0x30]  ; Save R12
+  move.d   $r13,[reg+0x34]  ; Save R13
+  move.d   $sp,[reg+0x38]   ; Save SP (R14)
+  move     $irp,[reg+0x3c]  ; Save the address in PC (R15)
+  clear.b  [reg+0x40]      ; Clear P0
+  move     $vr,[reg+0x41]   ; Save special register P1,
+  clear.w  [reg+0x42]      ; Clear P4
+  move     $ccr,[reg+0x44]  ; Save special register CCR
+  move     $mof,[reg+0x46]  ; P7
+  clear.d  [reg+0x4A]      ; Clear P8
+  move     $ibr,[reg+0x4E]  ; P9,
+  move     $irp,[reg+0x52]  ; P10,
+  move     $srp,[reg+0x56]  ; P11,
+  move     $dtp0,[reg+0x5A] ; P12, register BAR, assembler might not know BAR
+                            ; P13, register DCCR already saved
+;; Due to the old assembler-versions BRP might not be recognized
+  .word 0xE670              ; move brp,r0
+  move.d   $r0,[reg+0x62]   ; Save the return address in BRP
+  move     $usp,[reg+0x66]  ; USP
+
+;; get the serial character (from debugport.c) and check if it is a ctrl-c
+
+  jsr getDebugChar
+  cmp.b 3, $r10
+  bne goback
+  nop
+
+;;
+;; Handle the communication
+;;
+  move.d   internal_stack+1020,$sp ; Use the internal stack
+  moveq    2,$r10                   ; SIGINT
+  jsr      handle_exception       ; Interactive routine
+
+goback:
+;;
+;; Return to the caller
+;;
+   move.d  [reg],$r0         ; Restore R0
+   move.d  [reg+0x04],$r1    ; Restore R1
+   move.d  [reg+0x08],$r2    ; Restore R2
+   move.d  [reg+0x0C],$r3    ; Restore R3
+   move.d  [reg+0x10],$r4    ; Restore R4
+   move.d  [reg+0x14],$r5    ; Restore R5
+   move.d  [reg+0x18],$r6    ; Restore R6
+   move.d  [reg+0x1C],$r7    ; Restore R7
+   move.d  [reg+0x20],$r8    ; Restore R8
+   move.d  [reg+0x24],$r9    ; Restore R9
+   move.d  [reg+0x28],$r10   ; Restore R10
+   move.d  [reg+0x2C],$r11   ; Restore R11
+   move.d  [reg+0x30],$r12   ; Restore R12
+   move.d  [reg+0x34],$r13   ; Restore R13
+;;
+;; FIXME: Which registers should be restored?
+;;
+   move.d  [reg+0x38],$sp    ; Restore SP (R14)
+   move    [reg+0x56],$srp   ; Restore the subroutine return pointer.
+   move    [reg+0x5E],$dccr  ; Restore DCCR
+   move    [reg+0x66],$usp   ; Restore USP
+   reti                      ; Return from the interrupt routine
+   nop
+");
+
+/* Use this static breakpoint in the start-up only. */
+
+void
+breakpoint(void)
+{
+	kgdb_started = 1;
+	is_dyn_brkp = 0;     /* This is a static, not a dynamic breakpoint. */
+	__asm__ volatile ("break 8"); /* Jump to handle_breakpoint. */
+}
+
+/* initialize kgdb. doesn't break into the debugger, but sets up irq and ports */
+
+void
+kgdb_init(void)
+{
+	/* could initialize debug port as well but it's done in head.S already... */
+
+        /* breakpoint handler is now set in irq.c */
+	set_int_vector(8, kgdb_handle_serial);
+	
+	enableDebugIRQ();
+}
+
+/****************************** End of file **********************************/
diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c
new file mode 100644
index 0000000..87ff377
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/process.c
@@ -0,0 +1,270 @@
+/* $Id: process.c,v 1.9 2004/10/19 13:07:37 starvik Exp $
+ * 
+ *  linux/arch/cris/kernel/process.c
+ *
+ *  Copyright (C) 1995  Linus Torvalds
+ *  Copyright (C) 2000-2002  Axis Communications AB
+ *
+ *  Authors:   Bjorn Wesen (bjornw@axis.com)
+ *             Mikael Starvik (starvik@axis.com)
+ *
+ * This file handles the architecture-dependent parts of process handling..
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <asm/arch/svinto.h>
+#include <linux/init.h>
+
+#ifdef CONFIG_ETRAX_GPIO
+void etrax_gpio_wake_up_check(void); /* drivers/gpio.c */
+#endif
+
+/*
+ * We use this if we don't have any better
+ * idle routine..
+ */
+void default_idle(void)
+{
+#ifdef CONFIG_ETRAX_GPIO
+  etrax_gpio_wake_up_check();
+#endif
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+
+void exit_thread(void)
+{
+	/* Nothing needs to be done.  */
+}
+
+/* if the watchdog is enabled, we can simply disable interrupts and go
+ * into an eternal loop, and the watchdog will reset the CPU after 0.1s
+ * if on the other hand the watchdog wasn't enabled, we just enable it and wait
+ */
+
+void hard_reset_now (void)
+{
+	/*
+	 * Don't declare this variable elsewhere.  We don't want any other
+	 * code to know about it than the watchdog handler in entry.S and
+	 * this code, implementing hard reset through the watchdog.
+	 */
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+	extern int cause_of_death;
+#endif
+
+	printk("*** HARD RESET ***\n");
+	local_irq_disable();
+
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+	cause_of_death = 0xbedead;
+#else
+	/* Since we dont plan to keep on reseting the watchdog,
+	   the key can be arbitrary hence three */
+	*R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, 3) |
+		IO_STATE(R_WATCHDOG, enable, start);
+#endif
+
+	while(1) /* waiting for RETRIBUTION! */ ;
+}
+
+/*
+ * Return saved PC of a blocked thread.
+ */
+unsigned long thread_saved_pc(struct task_struct *t)
+{
+	return (unsigned long)user_regs(t->thread_info)->irp;
+}
+
+static void kernel_thread_helper(void* dummy, int (*fn)(void *), void * arg)
+{
+  fn(arg);
+  do_exit(-1); /* Should never be called, return bad exit value */
+}
+
+/*
+ * Create a kernel thread
+ */
+int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+	struct pt_regs regs;
+
+	memset(&regs, 0, sizeof(regs));
+
+        /* Don't use r10 since that is set to 0 in copy_thread */
+	regs.r11 = (unsigned long)fn;
+	regs.r12 = (unsigned long)arg;
+	regs.irp = (unsigned long)kernel_thread_helper;
+
+	/* Ok, create the new process.. */
+        return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
+}
+
+/* setup the child's kernel stack with a pt_regs and switch_stack on it.
+ * it will be un-nested during _resume and _ret_from_sys_call when the
+ * new thread is scheduled.
+ *
+ * also setup the thread switching structure which is used to keep
+ * thread-specific data during _resumes.
+ *
+ */
+asmlinkage void ret_from_fork(void);
+
+int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+		unsigned long unused,
+		struct task_struct *p, struct pt_regs *regs)
+{
+	struct pt_regs * childregs;
+	struct switch_stack *swstack;
+	
+	/* put the pt_regs structure at the end of the new kernel stack page and fix it up
+	 * remember that the task_struct doubles as the kernel stack for the task
+	 */
+
+	childregs = user_regs(p->thread_info);        
+        
+	*childregs = *regs;  /* struct copy of pt_regs */
+        
+        p->set_child_tid = p->clear_child_tid = NULL;
+
+        childregs->r10 = 0;  /* child returns 0 after a fork/clone */
+	
+	/* put the switch stack right below the pt_regs */
+
+	swstack = ((struct switch_stack *)childregs) - 1;
+
+	swstack->r9 = 0; /* parameter to ret_from_sys_call, 0 == dont restart the syscall */
+
+	/* we want to return into ret_from_sys_call after the _resume */
+
+	swstack->return_ip = (unsigned long) ret_from_fork; /* Will call ret_from_sys_call */
+	
+	/* fix the user-mode stackpointer */
+
+	p->thread.usp = usp;	
+
+	/* and the kernel-mode one */
+
+	p->thread.ksp = (unsigned long) swstack;
+
+#ifdef DEBUG
+	printk("copy_thread: new regs at 0x%p, as shown below:\n", childregs);
+	show_registers(childregs);
+#endif
+
+	return 0;
+}
+
+/* 
+ * Be aware of the "magic" 7th argument in the four system-calls below.
+ * They need the latest stackframe, which is put as the 7th argument by
+ * entry.S. The previous arguments are dummies or actually used, but need
+ * to be defined to reach the 7th argument.
+ *
+ * N.B.: Another method to get the stackframe is to use current_regs(). But
+ * it returns the latest stack-frame stacked when going from _user mode_ and
+ * some of these (at least sys_clone) are called from kernel-mode sometimes
+ * (for example during kernel_thread, above) and thus cannot use it. Thus,
+ * to be sure not to get any surprises, we use the method for the other calls
+ * as well.
+ */
+
+asmlinkage int sys_fork(long r10, long r11, long r12, long r13, long mof, long srp,
+			struct pt_regs *regs)
+{
+	return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL);
+}
+
+/* if newusp is 0, we just grab the old usp */
+/* FIXME: Is parent_tid/child_tid really third/fourth argument? Update lib? */
+asmlinkage int sys_clone(unsigned long newusp, unsigned long flags,
+			 int* parent_tid, int* child_tid, long mof, long srp,
+			 struct pt_regs *regs)
+{
+	if (!newusp)
+		newusp = rdusp();
+	return do_fork(flags, newusp, regs, 0, parent_tid, child_tid);
+}
+
+/* vfork is a system call in i386 because of register-pressure - maybe
+ * we can remove it and handle it in libc but we put it here until then.
+ */
+
+asmlinkage int sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp,
+			 struct pt_regs *regs)
+{
+        return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL);
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+asmlinkage int sys_execve(const char *fname, char **argv, char **envp,
+			  long r13, long mof, long srp, 
+			  struct pt_regs *regs)
+{
+	int error;
+	char *filename;
+
+	filename = getname(fname);
+	error = PTR_ERR(filename);
+
+	if (IS_ERR(filename))
+	        goto out;
+	error = do_execve(filename, argv, envp, regs);
+	putname(filename);
+ out:
+	return error;
+}
+
+unsigned long get_wchan(struct task_struct *p)
+{
+#if 0
+	/* YURGH. TODO. */
+
+        unsigned long ebp, esp, eip;
+        unsigned long stack_page;
+        int count = 0;
+        if (!p || p == current || p->state == TASK_RUNNING)
+                return 0;
+        stack_page = (unsigned long)p;
+        esp = p->thread.esp;
+        if (!stack_page || esp < stack_page || esp > 8188+stack_page)
+                return 0;
+        /* include/asm-i386/system.h:switch_to() pushes ebp last. */
+        ebp = *(unsigned long *) esp;
+        do {
+                if (ebp < stack_page || ebp > 8184+stack_page)
+                        return 0;
+                eip = *(unsigned long *) (ebp+4);
+		if (!in_sched_functions(eip))
+			return eip;
+                ebp = *(unsigned long *) ebp;
+        } while (count++ < 16);
+#endif
+        return 0;
+}
+#undef last_sched
+#undef first_sched
+
+void show_regs(struct pt_regs * regs)
+{
+	unsigned long usp = rdusp();
+	printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n",
+	       regs->irp, regs->srp, regs->dccr, usp, regs->mof );
+	printk(" r0: %08lx  r1: %08lx   r2: %08lx  r3: %08lx\n",
+	       regs->r0, regs->r1, regs->r2, regs->r3);
+	printk(" r4: %08lx  r5: %08lx   r6: %08lx  r7: %08lx\n",
+	       regs->r4, regs->r5, regs->r6, regs->r7);
+	printk(" r8: %08lx  r9: %08lx  r10: %08lx r11: %08lx\n",
+	       regs->r8, regs->r9, regs->r10, regs->r11);
+	printk("r12: %08lx r13: %08lx oR10: %08lx\n",
+	       regs->r12, regs->r13, regs->orig_r10);
+}
+
diff --git a/arch/cris/arch-v10/kernel/ptrace.c b/arch/cris/arch-v10/kernel/ptrace.c
new file mode 100644
index 0000000..da15db8
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/ptrace.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2000-2003, Axis Communications AB.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+
+#include <asm/uaccess.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+
+/* 
+ * Determines which bits in DCCR the user has access to.
+ * 1 = access, 0 = no access.
+ */
+#define DCCR_MASK 0x0000001f     /* XNZVC */
+
+/*
+ * Get contents of register REGNO in task TASK.
+ */
+inline long get_reg(struct task_struct *task, unsigned int regno)
+{
+	/* USP is a special case, it's not in the pt_regs struct but
+	 * in the tasks thread struct
+	 */
+
+	if (regno == PT_USP)
+		return task->thread.usp;
+	else if (regno < PT_MAX)
+		return ((unsigned long *)user_regs(task->thread_info))[regno];
+	else
+		return 0;
+}
+
+/*
+ * Write contents of register REGNO in task TASK.
+ */
+inline int put_reg(struct task_struct *task, unsigned int regno,
+			  unsigned long data)
+{
+	if (regno == PT_USP)
+		task->thread.usp = data;
+	else if (regno < PT_MAX)
+		((unsigned long *)user_regs(task->thread_info))[regno] = data;
+	else
+		return -1;
+	return 0;
+}
+
+/*
+ * Called by kernel/ptrace.c when detaching.
+ *
+ * Make sure the single step bit is not set.
+ */
+void 
+ptrace_disable(struct task_struct *child)
+{
+       /* Todo - pending singlesteps? */
+}
+
+/* 
+ * Note that this implementation of ptrace behaves differently from vanilla
+ * ptrace.  Contrary to what the man page says, in the PTRACE_PEEKTEXT,
+ * PTRACE_PEEKDATA, and PTRACE_PEEKUSER requests the data variable is not
+ * ignored.  Instead, the data variable is expected to point at a location
+ * (in user space) where the result of the ptrace call is written (instead of
+ * being returned).
+ */
+asmlinkage int 
+sys_ptrace(long request, long pid, long addr, long data)
+{
+	struct task_struct *child;
+	int ret;
+	unsigned long __user *datap = (unsigned long __user *)data;
+
+	lock_kernel();
+	ret = -EPERM;
+	
+	if (request == PTRACE_TRACEME) {
+		if (current->ptrace & PT_PTRACED)
+			goto out;
+
+		current->ptrace |= PT_PTRACED;
+		ret = 0;
+		goto out;
+	}
+	
+	ret = -ESRCH;
+	read_lock(&tasklist_lock);
+	child = find_task_by_pid(pid);
+	
+	if (child)
+		get_task_struct(child);
+	
+	read_unlock(&tasklist_lock);
+	
+	if (!child)
+		goto out;
+	
+	ret = -EPERM;
+	
+	if (pid == 1)		/* Leave the init process alone! */
+		goto out_tsk;
+	
+	if (request == PTRACE_ATTACH) {
+		ret = ptrace_attach(child);
+		goto out_tsk;
+	}
+	
+	ret = ptrace_check_attach(child, request == PTRACE_KILL);
+	if (ret < 0)
+		goto out_tsk;
+
+	switch (request) {
+		/* Read word at location address. */ 
+		case PTRACE_PEEKTEXT:
+		case PTRACE_PEEKDATA: {
+			unsigned long tmp;
+			int copied;
+
+			copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+			ret = -EIO;
+			
+			if (copied != sizeof(tmp))
+				break;
+			
+			ret = put_user(tmp,datap);
+			break;
+		}
+
+		/* Read the word at location address in the USER area. */
+		case PTRACE_PEEKUSR: {
+			unsigned long tmp;
+
+			ret = -EIO;
+			if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
+				break;
+
+			tmp = get_reg(child, addr >> 2);
+			ret = put_user(tmp, datap);
+			break;
+		}
+		
+		/* Write the word at location address. */
+		case PTRACE_POKETEXT:
+		case PTRACE_POKEDATA:
+			ret = 0;
+			
+			if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
+				break;
+			
+			ret = -EIO;
+			break;
+ 
+ 		/* Write the word at location address in the USER area. */
+		case PTRACE_POKEUSR:
+			ret = -EIO;
+			if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
+				break;
+
+			addr >>= 2;
+
+			if (addr == PT_DCCR) {
+				/* don't allow the tracing process to change stuff like
+				 * interrupt enable, kernel/user bit, dma enables etc.
+				 */
+				data &= DCCR_MASK;
+				data |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
+			}
+			if (put_reg(child, addr, data))
+				break;
+			ret = 0;
+			break;
+
+		case PTRACE_SYSCALL:
+		case PTRACE_CONT:
+			ret = -EIO;
+			
+			if ((unsigned long) data > _NSIG)
+				break;
+                        
+			if (request == PTRACE_SYSCALL) {
+				set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+			}
+			else {
+				clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+			}
+			
+			child->exit_code = data;
+			
+			/* TODO: make sure any pending breakpoint is killed */
+			wake_up_process(child);
+			ret = 0;
+			
+			break;
+		
+ 		/* Make the child exit by sending it a sigkill. */
+		case PTRACE_KILL:
+			ret = 0;
+			
+			if (child->state == TASK_ZOMBIE)
+				break;
+			
+			child->exit_code = SIGKILL;
+			
+			/* TODO: make sure any pending breakpoint is killed */
+			wake_up_process(child);
+			break;
+
+		/* Set the trap flag. */
+		case PTRACE_SINGLESTEP:
+			ret = -EIO;
+			
+			if ((unsigned long) data > _NSIG)
+				break;
+			
+			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+
+			/* TODO: set some clever breakpoint mechanism... */
+
+			child->exit_code = data;
+			wake_up_process(child);
+			ret = 0;
+			break;
+
+		case PTRACE_DETACH:
+			ret = ptrace_detach(child, data);
+			break;
+
+		/* Get all GP registers from the child. */
+		case PTRACE_GETREGS: {
+		  	int i;
+			unsigned long tmp;
+			
+			for (i = 0; i <= PT_MAX; i++) {
+				tmp = get_reg(child, i);
+				
+				if (put_user(tmp, datap)) {
+					ret = -EFAULT;
+					goto out_tsk;
+				}
+				
+				data += sizeof(long);
+			}
+
+			ret = 0;
+			break;
+		}
+
+		/* Set all GP registers in the child. */
+		case PTRACE_SETREGS: {
+			int i;
+			unsigned long tmp;
+			
+			for (i = 0; i <= PT_MAX; i++) {
+				if (get_user(tmp, datap)) {
+					ret = -EFAULT;
+					goto out_tsk;
+				}
+				
+				if (i == PT_DCCR) {
+					tmp &= DCCR_MASK;
+					tmp |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
+				}
+				
+				put_reg(child, i, tmp);
+				data += sizeof(long);
+			}
+			
+			ret = 0;
+			break;
+		}
+
+		default:
+			ret = ptrace_request(child, request, addr, data);
+			break;
+	}
+out_tsk:
+	put_task_struct(child);
+out:
+	unlock_kernel();
+	return ret;
+}
+
+void do_syscall_trace(void)
+{
+	if (!test_thread_flag(TIF_SYSCALL_TRACE))
+		return;
+	
+	if (!(current->ptrace & PT_PTRACED))
+		return;
+	
+	/* the 0x80 provides a way for the tracing parent to distinguish
+	   between a syscall stop and SIGTRAP delivery */
+	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+				 ? 0x80 : 0));
+	
+	/*
+	 * This isn't the same as continuing with a signal, but it will do for
+	 * normal use.
+	 */
+	if (current->exit_code) {
+		send_sig(current->exit_code, current, 1);
+		current->exit_code = 0;
+	}
+}
diff --git a/arch/cris/arch-v10/kernel/setup.c b/arch/cris/arch-v10/kernel/setup.c
new file mode 100644
index 0000000..b668d7f
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/setup.c
@@ -0,0 +1,103 @@
+/*
+ *
+ *  linux/arch/cris/arch-v10/kernel/setup.c
+ *
+ *  Copyright (C) 1995  Linus Torvalds
+ *  Copyright (c) 2001-2002  Axis Communications AB
+ */
+
+/*
+ * This file handles the architecture-dependent parts of initialization
+ */
+
+#include <linux/config.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+
+#ifdef CONFIG_PROC_FS
+#define HAS_FPU		0x0001
+#define HAS_MMU		0x0002
+#define HAS_ETHERNET100	0x0004
+#define HAS_TOKENRING	0x0008
+#define HAS_SCSI	0x0010
+#define HAS_ATA		0x0020
+#define HAS_USB		0x0040
+#define HAS_IRQ_BUG	0x0080
+#define HAS_MMU_BUG	0x0100
+
+static struct cpu_info {
+	char *model;
+	unsigned short cache;
+	unsigned short flags;
+} cpu_info[] = {
+	/* The first four models will never ever run this code and are
+	   only here for display.  */
+	{ "ETRAX 1",         0, 0 },
+	{ "ETRAX 2",         0, 0 },
+	{ "ETRAX 3",         0, HAS_TOKENRING },
+	{ "ETRAX 4",         0, HAS_TOKENRING | HAS_SCSI },
+	{ "Unknown",         0, 0 },
+	{ "Unknown",         0, 0 },
+	{ "Unknown",         0, 0 },
+	{ "Simulator",       8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA },
+	{ "ETRAX 100",       8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_IRQ_BUG },
+	{ "ETRAX 100",       8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA },
+	{ "ETRAX 100LX",     8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU | HAS_MMU_BUG },
+	{ "ETRAX 100LX v2",  8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU  },
+	{ "Unknown",         0, 0 }  /* This entry MUST be the last */
+};
+
+int show_cpuinfo(struct seq_file *m, void *v)
+{
+	unsigned long revision;
+	struct cpu_info *info;
+
+	/* read the version register in the CPU and print some stuff */
+
+	revision = rdvr();
+
+	if (revision >= sizeof cpu_info/sizeof *cpu_info)
+		info = &cpu_info[sizeof cpu_info/sizeof *cpu_info - 1];
+	else
+		info = &cpu_info[revision];
+
+	return seq_printf(m,
+		       "processor\t: 0\n" 
+		       "cpu\t\t: CRIS\n"
+		       "cpu revision\t: %lu\n"
+		       "cpu model\t: %s\n"
+		       "cache size\t: %d kB\n"
+		       "fpu\t\t: %s\n"
+		       "mmu\t\t: %s\n"
+		       "mmu DMA bug\t: %s\n"
+		       "ethernet\t: %s Mbps\n"
+		       "token ring\t: %s\n"
+		       "scsi\t\t: %s\n"
+		       "ata\t\t: %s\n"
+		       "usb\t\t: %s\n"
+		       "bogomips\t: %lu.%02lu\n",
+
+		       revision,
+		       info->model,
+		       info->cache,
+		       info->flags & HAS_FPU ? "yes" : "no",
+		       info->flags & HAS_MMU ? "yes" : "no",
+		       info->flags & HAS_MMU_BUG ? "yes" : "no",
+		       info->flags & HAS_ETHERNET100 ? "10/100" : "10",
+		       info->flags & HAS_TOKENRING ? "4/16 Mbps" : "no",
+		       info->flags & HAS_SCSI ? "yes" : "no",
+		       info->flags & HAS_ATA ? "yes" : "no",
+		       info->flags & HAS_USB ? "yes" : "no",
+		       (loops_per_jiffy * HZ + 500) / 500000,
+		       ((loops_per_jiffy * HZ + 500) / 5000) % 100);
+}
+
+#endif /* CONFIG_PROC_FS */
+
+void
+show_etrax_copyright(void)
+{
+	printk(KERN_INFO
+               "Linux/CRIS port on ETRAX 100LX (c) 2001 Axis Communications AB\n");
+}
diff --git a/arch/cris/arch-v10/kernel/shadows.c b/arch/cris/arch-v10/kernel/shadows.c
new file mode 100644
index 0000000..561a890
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/shadows.c
@@ -0,0 +1,36 @@
+/* $Id: shadows.c,v 1.1 2001/12/17 13:59:27 bjornw Exp $
+ * 
+ * Various shadow registers. Defines for these are in include/asm-etrax100/io.h
+ */
+
+/* Shadows for internal Etrax-registers */
+
+unsigned long genconfig_shadow;
+unsigned long port_g_data_shadow;
+unsigned char port_pa_dir_shadow;
+unsigned char port_pa_data_shadow;
+unsigned char port_pb_i2c_shadow;
+unsigned char port_pb_config_shadow;
+unsigned char port_pb_dir_shadow;
+unsigned char port_pb_data_shadow;
+unsigned long r_timer_ctrl_shadow;
+
+/* Shadows for external I/O port registers.
+ * These are only usable if there actually IS a latch connected
+ * to the corresponding external chip-select pin.
+ *
+ * A common usage is that CSP0 controls LED's and CSP4 video chips.
+ */
+
+unsigned long port_cse1_shadow;
+unsigned long port_csp0_shadow;
+unsigned long port_csp4_shadow;
+
+/* Corresponding addresses for the ports.
+ * These are initialized in arch/cris/mm/init.c using ioremap.
+ */
+
+volatile unsigned long *port_cse1_addr;
+volatile unsigned long *port_csp0_addr;
+volatile unsigned long *port_csp4_addr;
+
diff --git a/arch/cris/arch-v10/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c
new file mode 100644
index 0000000..85e0032
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/signal.c
@@ -0,0 +1,580 @@
+/*
+ *  linux/arch/cris/kernel/signal.c
+ *
+ *  Based on arch/i386/kernel/signal.c by
+ *     Copyright (C) 1991, 1992  Linus Torvalds
+ *     1997-11-28  Modified for POSIX.1b signals by Richard Henderson *
+ *
+ *  Ideas also taken from arch/arm.
+ *
+ *  Copyright (C) 2000, 2001 Axis Communications AB
+ *
+ *  Authors:  Bjorn Wesen (bjornw@axis.com)
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+
+#include <asm/processor.h>
+#include <asm/ucontext.h>
+#include <asm/uaccess.h>
+
+#define DEBUG_SIG 0
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+/* a syscall in Linux/CRIS is a break 13 instruction which is 2 bytes */
+/* manipulate regs so that upon return, it will be re-executed */
+
+/* We rely on that pc points to the instruction after "break 13", so the
+ * library must never do strange things like putting it in a delay slot.
+ */
+#define RESTART_CRIS_SYS(regs) regs->r10 = regs->orig_r10; regs->irp -= 2;
+
+int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs);
+
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.  Define 
+ * dummy arguments to be able to reach the regs argument.  (Note that this
+ * arrangement relies on old_sigset_t occupying one register.)
+ */
+int
+sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof, 
+               long srp, struct pt_regs *regs)
+{
+	sigset_t saveset;
+
+	mask &= _BLOCKABLE;
+	spin_lock_irq(&current->sighand->siglock);
+	saveset = current->blocked;
+	siginitset(&current->blocked, mask);
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	regs->r10 = -EINTR;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal(0, &saveset, regs))
+			/* We will get here twice: once to call the signal
+			   handler, then again to return from the
+			   sigsuspend system call.  When calling the
+			   signal handler, R10 holds the signal number as
+			   set through do_signal.  The sigsuspend call
+			   will return with the restored value set above;
+			   always -EINTR.  */
+			return regs->r10;
+	}
+}
+
+/* Define dummy arguments to be able to reach the regs argument.  (Note that
+ * this arrangement relies on size_t occupying one register.)
+ */
+int
+sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, long r12, long r13, 
+                  long mof, long srp, struct pt_regs *regs)
+{
+	sigset_t saveset, newset;
+
+	/* XXX: Don't preclude handling different sized sigset_t's.  */
+	if (sigsetsize != sizeof(sigset_t))
+		return -EINVAL;
+
+	if (copy_from_user(&newset, unewset, sizeof(newset)))
+		return -EFAULT;
+	sigdelsetmask(&newset, ~_BLOCKABLE);
+
+	spin_lock_irq(&current->sighand->siglock);
+	saveset = current->blocked;
+	current->blocked = newset;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	regs->r10 = -EINTR;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal(0, &saveset, regs))
+			/* We will get here twice: once to call the signal
+			   handler, then again to return from the
+			   sigsuspend system call.  When calling the
+			   signal handler, R10 holds the signal number as
+			   set through do_signal.  The sigsuspend call
+			   will return with the restored value set above;
+			   always -EINTR.  */
+			return regs->r10;
+	}
+}
+
+int 
+sys_sigaction(int sig, const struct old_sigaction __user *act,
+	      struct old_sigaction *oact)
+{
+	struct k_sigaction new_ka, old_ka;
+	int ret;
+
+	if (act) {
+		old_sigset_t mask;
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
+		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+			return -EFAULT;
+		__get_user(new_ka.sa.sa_flags, &act->sa_flags);
+		__get_user(mask, &act->sa_mask);
+		siginitset(&new_ka.sa.sa_mask, mask);
+	}
+
+	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+	if (!ret && oact) {
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+			return -EFAULT;
+		__put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+		__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+	}
+
+	return ret;
+}
+
+int
+sys_sigaltstack(const stack_t *uss, stack_t __user *uoss)
+{
+	return do_sigaltstack(uss, uoss, rdusp());
+}
+
+
+/*
+ * Do a signal return; undo the signal stack.
+ */
+
+struct sigframe {
+	struct sigcontext sc;
+	unsigned long extramask[_NSIG_WORDS-1];
+	unsigned char retcode[8];  /* trampoline code */
+};
+
+struct rt_sigframe {
+	struct siginfo *pinfo;
+	void *puc;
+	struct siginfo info;
+	struct ucontext uc;
+	unsigned char retcode[8];  /* trampoline code */
+};
+
+
+static int
+restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
+{
+	unsigned int err = 0;
+	unsigned long old_usp;
+
+        /* Always make any pending restarted system calls return -EINTR */
+	current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+	/* restore the regs from &sc->regs (same as sc, since regs is first)
+	 * (sc is already checked for VERIFY_READ since the sigframe was
+	 *  checked in sys_sigreturn previously)
+	 */
+
+	if (__copy_from_user(regs, sc, sizeof(struct pt_regs)))
+                goto badframe;
+
+	/* make sure the U-flag is set so user-mode cannot fool us */
+
+	regs->dccr |= 1 << 8;
+
+	/* restore the old USP as it was before we stacked the sc etc.
+	 * (we cannot just pop the sigcontext since we aligned the sp and
+	 *  stuff after pushing it)
+	 */
+
+	err |= __get_user(old_usp, &sc->usp);
+
+	wrusp(old_usp);
+
+	/* TODO: the other ports use regs->orig_XX to disable syscall checks
+	 * after this completes, but we don't use that mechanism. maybe we can
+	 * use it now ? 
+	 */
+
+	return err;
+
+badframe:
+	return 1;
+}
+
+/* Define dummy arguments to be able to reach the regs argument.  */
+
+asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof, 
+                             long srp, struct pt_regs *regs)
+{
+	struct sigframe __user *frame = (struct sigframe *)rdusp();
+	sigset_t set;
+
+        /*
+         * Since we stacked the signal on a dword boundary,
+         * then frame should be dword aligned here.  If it's
+         * not, then the user is trying to mess with us.
+         */
+        if (((long)frame) & 3)
+                goto badframe;
+
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+	if (__get_user(set.sig[0], &frame->sc.oldmask)
+	    || (_NSIG_WORDS > 1
+		&& __copy_from_user(&set.sig[1], frame->extramask,
+				    sizeof(frame->extramask))))
+		goto badframe;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sighand->siglock);
+	current->blocked = set;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+	
+	if (restore_sigcontext(regs, &frame->sc))
+		goto badframe;
+
+	/* TODO: SIGTRAP when single-stepping as in arm ? */
+
+	return regs->r10;
+
+badframe:
+	force_sig(SIGSEGV, current);
+	return 0;
+}	
+
+/* Define dummy arguments to be able to reach the regs argument.  */
+
+asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13, 
+                                long mof, long srp, struct pt_regs *regs)
+{
+	struct rt_sigframe __user *frame = (struct rt_sigframe *)rdusp();
+	sigset_t set;
+
+        /*
+         * Since we stacked the signal on a dword boundary,
+         * then frame should be dword aligned here.  If it's
+         * not, then the user is trying to mess with us.
+         */
+        if (((long)frame) & 3)
+                goto badframe;
+
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+		goto badframe;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sighand->siglock);
+	current->blocked = set;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+	
+	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
+		goto badframe;
+
+	if (do_sigaltstack(&frame->uc.uc_stack, NULL, rdusp()) == -EFAULT)
+		goto badframe;
+
+	return regs->r10;
+
+badframe:
+	force_sig(SIGSEGV, current);
+	return 0;
+}	
+
+/*
+ * Set up a signal frame.
+ */
+
+static int
+setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned long mask)
+{
+	int err = 0;
+	unsigned long usp = rdusp();
+
+	/* copy the regs. they are first in sc so we can use sc directly */
+
+	err |= __copy_to_user(sc, regs, sizeof(struct pt_regs));
+
+        /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
+           the signal handler. The frametype will be restored to its previous
+           value in restore_sigcontext. */
+        regs->frametype = CRIS_FRAME_NORMAL;
+
+	/* then some other stuff */
+
+	err |= __put_user(mask, &sc->oldmask);
+
+	err |= __put_user(usp, &sc->usp);
+
+	return err;
+}
+
+/* figure out where we want to put the new signal frame - usually on the stack */
+
+static inline void __user *
+get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
+{
+	unsigned long sp = rdusp();
+
+	/* This is the X/Open sanctioned signal stack switching.  */
+	if (ka->sa.sa_flags & SA_ONSTACK) {
+		if (! on_sig_stack(sp))
+			sp = current->sas_ss_sp + current->sas_ss_size;
+	}
+
+	/* make sure the frame is dword-aligned */
+
+	sp &= ~3;
+
+	return (void __user*)(sp - frame_size);
+}
+
+/* grab and setup a signal frame.
+ * 
+ * basically we stack a lot of state info, and arrange for the
+ * user-mode program to return to the kernel using either a
+ * trampoline which performs the syscall sigreturn, or a provided
+ * user-mode trampoline.
+ */
+
+static void setup_frame(int sig, struct k_sigaction *ka,
+			sigset_t *set, struct pt_regs * regs)
+{
+	struct sigframe __user *frame;
+	unsigned long return_ip;
+	int err = 0;
+
+	frame = get_sigframe(ka, regs, sizeof(*frame));
+
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+		goto give_sigsegv;
+
+	err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
+	if (err)
+		goto give_sigsegv;
+
+	if (_NSIG_WORDS > 1) {
+		err |= __copy_to_user(frame->extramask, &set->sig[1],
+				      sizeof(frame->extramask));
+	}
+	if (err)
+		goto give_sigsegv;
+
+	/* Set up to return from userspace.  If provided, use a stub
+	   already in userspace.  */
+	if (ka->sa.sa_flags & SA_RESTORER) {
+		return_ip = (unsigned long)ka->sa.sa_restorer;
+	} else {
+		/* trampoline - the desired return ip is the retcode itself */
+		return_ip = (unsigned long)&frame->retcode;
+		/* This is movu.w __NR_sigreturn, r9; break 13; */
+		err |= __put_user(0x9c5f,         (short __user*)(frame->retcode+0));
+		err |= __put_user(__NR_sigreturn, (short __user*)(frame->retcode+2));
+		err |= __put_user(0xe93d,         (short __user*)(frame->retcode+4));
+	}
+
+	if (err)
+		goto give_sigsegv;
+
+	/* Set up registers for signal handler */
+
+	regs->irp = (unsigned long) ka->sa.sa_handler;  /* what we enter NOW   */
+	regs->srp = return_ip;                          /* what we enter LATER */
+	regs->r10 = sig;                                /* first argument is signo */
+
+	/* actually move the usp to reflect the stacked frame */
+
+	wrusp((unsigned long)frame);
+
+	return;
+
+give_sigsegv:
+	force_sigsegv(sig, current);
+}
+
+static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+			   sigset_t *set, struct pt_regs * regs)
+{
+	struct rt_sigframe __user *frame;
+	unsigned long return_ip;
+	int err = 0;
+
+	frame = get_sigframe(ka, regs, sizeof(*frame));
+
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+		goto give_sigsegv;
+
+	err |= __put_user(&frame->info, &frame->pinfo);
+	err |= __put_user(&frame->uc, &frame->puc);
+	err |= copy_siginfo_to_user(&frame->info, info);
+	if (err)
+		goto give_sigsegv;
+
+	/* Clear all the bits of the ucontext we don't use.  */
+        err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
+
+	err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);
+
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
+	if (err)
+		goto give_sigsegv;
+
+	/* Set up to return from userspace.  If provided, use a stub
+	   already in userspace.  */
+	if (ka->sa.sa_flags & SA_RESTORER) {
+		return_ip = (unsigned long)ka->sa.sa_restorer;
+	} else {
+		/* trampoline - the desired return ip is the retcode itself */
+		return_ip = (unsigned long)&frame->retcode;
+		/* This is movu.w __NR_rt_sigreturn, r9; break 13; */
+		err |= __put_user(0x9c5f,            (short __user*)(frame->retcode+0));
+		err |= __put_user(__NR_rt_sigreturn, (short __user*)(frame->retcode+2));
+		err |= __put_user(0xe93d,            (short __user*)(frame->retcode+4));
+	}
+
+	if (err)
+		goto give_sigsegv;
+
+	/* TODO what is the current->exec_domain stuff and invmap ? */
+
+	/* Set up registers for signal handler */
+
+	regs->irp = (unsigned long) ka->sa.sa_handler;  /* what we enter NOW   */
+	regs->srp = return_ip;                          /* what we enter LATER */
+	regs->r10 = sig;                                /* first argument is signo */
+        regs->r11 = (unsigned long) &frame->info;       /* second argument is (siginfo_t *) */
+        regs->r12 = 0;                                  /* third argument is unused */
+
+	/* actually move the usp to reflect the stacked frame */
+
+	wrusp((unsigned long)frame);
+
+	return;
+
+give_sigsegv:
+	force_sigsegv(sig, current);
+}
+
+/*
+ * OK, we're invoking a handler
+ */	
+
+extern inline void
+handle_signal(int canrestart, unsigned long sig,
+	      siginfo_t *info, struct k_sigaction *ka,
+              sigset_t *oldset, struct pt_regs * regs)
+{
+	/* Are we from a system call? */
+	if (canrestart) {
+		/* If so, check system call restarting.. */
+		switch (regs->r10) {
+			case -ERESTART_RESTARTBLOCK:
+			case -ERESTARTNOHAND:
+				/* ERESTARTNOHAND means that the syscall should only be
+				   restarted if there was no handler for the signal, and since
+				   we only get here if there is a handler, we don't restart */
+				regs->r10 = -EINTR;
+				break;
+
+			case -ERESTARTSYS:
+				/* ERESTARTSYS means to restart the syscall if there is no
+				   handler or the handler was registered with SA_RESTART */
+				if (!(ka->sa.sa_flags & SA_RESTART)) {
+					regs->r10 = -EINTR;
+					break;
+				}
+			/* fallthrough */
+			case -ERESTARTNOINTR:
+				/* ERESTARTNOINTR means that the syscall should be called again
+				   after the signal handler returns. */
+				RESTART_CRIS_SYS(regs);
+		}
+	}
+
+	/* Set up the stack frame */
+	if (ka->sa.sa_flags & SA_SIGINFO)
+		setup_rt_frame(sig, ka, info, oldset, regs);
+	else
+		setup_frame(sig, ka, oldset, regs);
+
+	if (ka->sa.sa_flags & SA_ONESHOT)
+		ka->sa.sa_handler = SIG_DFL;
+
+	if (!(ka->sa.sa_flags & SA_NODEFER)) {
+		spin_lock_irq(&current->sighand->siglock);
+		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+		sigaddset(&current->blocked,sig);
+		recalc_sigpending();
+		spin_unlock_irq(&current->sighand->siglock);
+	}
+}
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ *
+ * Also note that the regs structure given here as an argument, is the latest
+ * pushed pt_regs. It may or may not be the same as the first pushed registers
+ * when the initial usermode->kernelmode transition took place. Therefore
+ * we can use user_mode(regs) to see if we came directly from kernel or user
+ * mode below.
+ */
+
+int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
+{
+	siginfo_t info;
+	int signr;
+        struct k_sigaction ka;
+
+	/*
+	 * We want the common case to go fast, which
+	 * is why we may in certain cases get here from
+	 * kernel mode. Just return without doing anything
+	 * if so.
+	 */
+	if (!user_mode(regs))
+		return 1;
+
+	if (!oldset)
+		oldset = &current->blocked;
+
+	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+	if (signr > 0) {
+		/* Whee!  Actually deliver the signal.  */
+		handle_signal(canrestart, signr, &info, &ka, oldset, regs);
+		return 1;
+	}
+
+	/* Did we come from a system call? */
+	if (canrestart) {
+		/* Restart the system call - no handlers present */
+		if (regs->r10 == -ERESTARTNOHAND ||
+		    regs->r10 == -ERESTARTSYS ||
+		    regs->r10 == -ERESTARTNOINTR) {
+			RESTART_CRIS_SYS(regs);
+		}
+		if (regs->r10 == -ERESTART_RESTARTBLOCK){
+			regs->r10 = __NR_restart_syscall;
+			regs->irp -= 2;
+		}
+	}
+	return 0;
+}
diff --git a/arch/cris/arch-v10/kernel/time.c b/arch/cris/arch-v10/kernel/time.c
new file mode 100644
index 0000000..6b7b4e0
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/time.c
@@ -0,0 +1,369 @@
+/* $Id: time.c,v 1.5 2004/09/29 06:12:46 starvik Exp $
+ *
+ *  linux/arch/cris/arch-v10/kernel/time.c
+ *
+ *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *  Copyright (C) 1999-2002 Axis Communications AB
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/timex.h>
+#include <linux/time.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/swap.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <asm/arch/svinto.h>
+#include <asm/types.h>
+#include <asm/signal.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <asm/rtc.h>
+
+/* define this if you need to use print_timestamp */
+/* it will make jiffies at 96 hz instead of 100 hz though */
+#undef USE_CASCADE_TIMERS
+
+extern void update_xtime_from_cmos(void);
+extern int set_rtc_mmss(unsigned long nowtime);
+extern int setup_irq(int, struct irqaction *);
+extern int have_rtc;
+
+unsigned long get_ns_in_jiffie(void)
+{
+	unsigned char timer_count, t1;
+	unsigned short presc_count;
+	unsigned long ns;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	local_irq_disable();
+	timer_count = *R_TIMER0_DATA;
+	presc_count = *R_TIM_PRESC_STATUS;  
+	/* presc_count might be wrapped */
+	t1 = *R_TIMER0_DATA;
+
+	if (timer_count != t1){
+		/* it wrapped, read prescaler again...  */
+		presc_count = *R_TIM_PRESC_STATUS;
+		timer_count = t1;
+	}
+	local_irq_restore(flags);
+	if (presc_count >= PRESCALE_VALUE/2 ){
+		presc_count =  PRESCALE_VALUE - presc_count + PRESCALE_VALUE/2;
+	} else {
+		presc_count =  PRESCALE_VALUE - presc_count - PRESCALE_VALUE/2;
+	}
+
+	ns = ( (TIMER0_DIV - timer_count) * ((1000000000/HZ)/TIMER0_DIV )) + 
+	     ( (presc_count) * (1000000000/PRESCALE_FREQ));
+	return ns;
+}
+
+unsigned long do_slow_gettimeoffset(void)
+{
+	unsigned long count, t1;
+	unsigned long usec_count = 0;
+	unsigned short presc_count;
+
+	static unsigned long count_p = TIMER0_DIV;/* for the first call after boot */
+	static unsigned long jiffies_p = 0;
+
+	/*
+	 * cache volatile jiffies temporarily; we have IRQs turned off. 
+	 */
+	unsigned long jiffies_t;
+
+	/* The timer interrupt comes from Etrax timer 0. In order to get
+	 * better precision, we check the current value. It might have
+	 * underflowed already though.
+	 */
+
+#ifndef CONFIG_SVINTO_SIM
+	/* Not available in the xsim simulator. */
+	count = *R_TIMER0_DATA;
+	presc_count = *R_TIM_PRESC_STATUS;  
+	/* presc_count might be wrapped */
+	t1 = *R_TIMER0_DATA;
+	if (count != t1){
+		/* it wrapped, read prescaler again...  */
+		presc_count = *R_TIM_PRESC_STATUS;
+		count = t1;
+	}
+#else
+	count = 0;
+	presc_count = 0;
+#endif
+
+ 	jiffies_t = jiffies;
+
+	/*
+	 * avoiding timer inconsistencies (they are rare, but they happen)...
+	 * there are one problem that must be avoided here:
+	 *  1. the timer counter underflows
+	 */
+	if( jiffies_t == jiffies_p ) {
+		if( count > count_p ) {
+			/* Timer wrapped, use new count and prescale 
+			 * increase the time corresponding to one jiffie
+			 */
+			usec_count = 1000000/HZ;
+		}
+	} else
+		jiffies_p = jiffies_t;
+        count_p = count;
+	if (presc_count >= PRESCALE_VALUE/2 ){
+		presc_count =  PRESCALE_VALUE - presc_count + PRESCALE_VALUE/2;
+	} else {
+		presc_count =  PRESCALE_VALUE - presc_count - PRESCALE_VALUE/2;
+	}
+	/* Convert timer value to usec */
+	usec_count += ( (TIMER0_DIV - count) * (1000000/HZ)/TIMER0_DIV ) +
+	              (( (presc_count) * (1000000000/PRESCALE_FREQ))/1000);
+
+	return usec_count;
+}
+
+/* Excerpt from the Etrax100 HSDD about the built-in watchdog:
+ *
+ * 3.10.4 Watchdog timer
+
+ * When the watchdog timer is started, it generates an NMI if the watchdog
+ * isn't restarted or stopped within 0.1 s. If it still isn't restarted or
+ * stopped after an additional 3.3 ms, the watchdog resets the chip.
+ * The watchdog timer is stopped after reset. The watchdog timer is controlled
+ * by the R_WATCHDOG register. The R_WATCHDOG register contains an enable bit
+ * and a 3-bit key value. The effect of writing to the R_WATCHDOG register is
+ * described in the table below:
+ * 
+ *   Watchdog    Value written:
+ *   state:      To enable:  To key:      Operation:
+ *   --------    ----------  -------      ----------
+ *   stopped         0         X          No effect.
+ *   stopped         1       key_val      Start watchdog with key = key_val.
+ *   started         0       ~key         Stop watchdog
+ *   started         1       ~key         Restart watchdog with key = ~key.
+ *   started         X       new_key_val  Change key to new_key_val.
+ * 
+ * Note: '~' is the bitwise NOT operator.
+ * 
+ */
+
+/* right now, starting the watchdog is the same as resetting it */
+#define start_watchdog reset_watchdog
+
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+static int watchdog_key = 0;  /* arbitrary number */
+#endif
+
+/* number of pages to consider "out of memory". it is normal that the memory
+ * is used though, so put this really low.
+ */
+
+#define WATCHDOG_MIN_FREE_PAGES 8
+
+void
+reset_watchdog(void)
+{
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+	/* only keep watchdog happy as long as we have memory left! */
+	if(nr_free_pages() > WATCHDOG_MIN_FREE_PAGES) {
+		/* reset the watchdog with the inverse of the old key */
+		watchdog_key ^= 0x7; /* invert key, which is 3 bits */
+		*R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) |
+			IO_STATE(R_WATCHDOG, enable, start);
+	}
+#endif
+}
+
+/* stop the watchdog - we still need the correct key */
+
+void 
+stop_watchdog(void)
+{
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+	watchdog_key ^= 0x7; /* invert key, which is 3 bits */
+	*R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) |
+		IO_STATE(R_WATCHDOG, enable, stop);
+#endif	
+}
+
+/* last time the cmos clock got updated */
+static long last_rtc_update = 0;
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+
+//static unsigned short myjiff; /* used by our debug routine print_timestamp */
+
+extern void cris_do_profile(struct pt_regs *regs);
+
+static inline irqreturn_t
+timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	/* acknowledge the timer irq */
+
+#ifdef USE_CASCADE_TIMERS
+	*R_TIMER_CTRL =
+		IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) |
+		IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) |
+		IO_STATE( R_TIMER_CTRL, i1, clr) |
+		IO_STATE( R_TIMER_CTRL, tm1, run) |
+		IO_STATE( R_TIMER_CTRL, clksel1, cascade0) |
+		IO_STATE( R_TIMER_CTRL, i0, clr) |
+		IO_STATE( R_TIMER_CTRL, tm0, run) |
+		IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz);
+#else
+	*R_TIMER_CTRL = r_timer_ctrl_shadow | 
+		IO_STATE(R_TIMER_CTRL, i0, clr);
+#endif
+
+	/* reset watchdog otherwise it resets us! */
+
+	reset_watchdog();
+	
+	/* call the real timer interrupt handler */
+
+	do_timer(regs);
+	
+        cris_do_profile(regs); /* Save profiling information */
+
+	/*
+	 * If we have an externally synchronized Linux clock, then update
+	 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+	 * called as close as possible to 500 ms before the new second starts.
+	 *
+	 * The division here is not time critical since it will run once in 
+	 * 11 minutes
+	 */
+	if ((time_status & STA_UNSYNC) == 0 &&
+	    xtime.tv_sec > last_rtc_update + 660 &&
+	    (xtime.tv_nsec / 1000) >= 500000 - (tick_nsec / 1000) / 2 &&
+	    (xtime.tv_nsec / 1000) <= 500000 + (tick_nsec / 1000) / 2) {
+		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 60 s */
+	}
+        return IRQ_HANDLED;
+}
+
+/* timer is SA_SHIRQ so drivers can add stuff to the timer irq chain
+ * it needs to be SA_INTERRUPT to make the jiffies update work properly
+ */
+
+static struct irqaction irq2  = { timer_interrupt, SA_SHIRQ | SA_INTERRUPT,
+				  CPU_MASK_NONE, "timer", NULL, NULL};
+
+void __init
+time_init(void)
+{	
+	/* probe for the RTC and read it if it exists 
+	 * Before the RTC can be probed the loops_per_usec variable needs 
+	 * to be initialized to make usleep work. A better value for 
+	 * loops_per_usec is calculated by the kernel later once the 
+	 * clock has started.  
+	 */
+	loops_per_usec = 50;
+
+	if(RTC_INIT() < 0) {
+		/* no RTC, start at 1980 */
+		xtime.tv_sec = 0;
+		xtime.tv_nsec = 0;
+		have_rtc = 0;
+	} else {		
+		/* get the current time */
+		have_rtc = 1;
+		update_xtime_from_cmos();
+	}
+
+	/*
+	 * Initialize wall_to_monotonic such that adding it to xtime will yield zero, the
+	 * tv_nsec field must be normalized (i.e., 0 <= nsec < NSEC_PER_SEC).
+	 */
+	set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec);
+
+	/* Setup the etrax timers
+	 * Base frequency is 25000 hz, divider 250 -> 100 HZ
+	 * In normal mode, we use timer0, so timer1 is free. In cascade
+	 * mode (which we sometimes use for debugging) both timers are used.
+	 * Remember that linux/timex.h contains #defines that rely on the
+	 * timer settings below (hz and divide factor) !!!
+	 */
+	
+#ifdef USE_CASCADE_TIMERS
+	*R_TIMER_CTRL =
+		IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) |
+		IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) |
+		IO_STATE( R_TIMER_CTRL, i1, nop) |
+		IO_STATE( R_TIMER_CTRL, tm1, stop_ld) |
+		IO_STATE( R_TIMER_CTRL, clksel1, cascade0) |
+		IO_STATE( R_TIMER_CTRL, i0, nop) |
+		IO_STATE( R_TIMER_CTRL, tm0, stop_ld) |
+		IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz);
+	
+	*R_TIMER_CTRL = r_timer_ctrl_shadow = 
+		IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) |
+		IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) |
+		IO_STATE( R_TIMER_CTRL, i1, nop) |
+		IO_STATE( R_TIMER_CTRL, tm1, run) |
+		IO_STATE( R_TIMER_CTRL, clksel1, cascade0) |
+		IO_STATE( R_TIMER_CTRL, i0, nop) |
+		IO_STATE( R_TIMER_CTRL, tm0, run) |
+		IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz);
+#else
+	*R_TIMER_CTRL = 
+		IO_FIELD(R_TIMER_CTRL, timerdiv1, 192)      | 
+		IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER0_DIV)      |
+		IO_STATE(R_TIMER_CTRL, i1,        nop)      | 
+		IO_STATE(R_TIMER_CTRL, tm1,       stop_ld)  |
+		IO_STATE(R_TIMER_CTRL, clksel1,   c19k2Hz)  |
+		IO_STATE(R_TIMER_CTRL, i0,        nop)      |
+		IO_STATE(R_TIMER_CTRL, tm0,       stop_ld)  |
+		IO_STATE(R_TIMER_CTRL, clksel0,   flexible);
+	
+	*R_TIMER_CTRL = r_timer_ctrl_shadow =
+		IO_FIELD(R_TIMER_CTRL, timerdiv1, 192)      | 
+		IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER0_DIV)      |
+		IO_STATE(R_TIMER_CTRL, i1,        nop)      |
+		IO_STATE(R_TIMER_CTRL, tm1,       run)      |
+		IO_STATE(R_TIMER_CTRL, clksel1,   c19k2Hz)  |
+		IO_STATE(R_TIMER_CTRL, i0,        nop)      |
+		IO_STATE(R_TIMER_CTRL, tm0,       run)      |
+		IO_STATE(R_TIMER_CTRL, clksel0,   flexible);
+
+	*R_TIMER_PRESCALE = PRESCALE_VALUE;
+#endif
+
+	*R_IRQ_MASK0_SET =
+		IO_STATE(R_IRQ_MASK0_SET, timer0, set); /* unmask the timer irq */
+	
+	/* now actually register the timer irq handler that calls timer_interrupt() */
+	
+	setup_irq(2, &irq2); /* irq 2 is the timer0 irq in etrax */
+
+	/* enable watchdog if we should use one */
+
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+	printk("Enabling watchdog...\n");
+	start_watchdog();
+
+	/* If we use the hardware watchdog, we want to trap it as an NMI
+	   and dump registers before it resets us.  For this to happen, we
+	   must set the "m" NMI enable flag (which once set, is unset only
+	   when an NMI is taken).
+
+	   The same goes for the external NMI, but that doesn't have any
+	   driver or infrastructure support yet.  */
+	asm ("setf m");
+
+	*R_IRQ_MASK0_SET =
+		IO_STATE(R_IRQ_MASK0_SET, watchdog_nmi, set);
+	*R_VECT_MASK_SET =
+		IO_STATE(R_VECT_MASK_SET, nmi, set);
+#endif
+}
diff --git a/arch/cris/arch-v10/kernel/traps.c b/arch/cris/arch-v10/kernel/traps.c
new file mode 100644
index 0000000..da491f4
--- /dev/null
+++ b/arch/cris/arch-v10/kernel/traps.c
@@ -0,0 +1,132 @@
+/* $Id: traps.c,v 1.2 2003/07/04 08:27:41 starvik Exp $
+ *
+ *  linux/arch/cris/arch-v10/traps.c
+ *
+ *  Heler functions for trap handlers
+ * 
+ *  Copyright (C) 2000-2002 Axis Communications AB
+ *
+ *  Authors:   Bjorn Wesen
+ *  	       Hans-Peter Nilsson
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/ptrace.h>
+#include <asm/uaccess.h>
+#include <asm/arch/sv_addr_ag.h>
+
+void 
+show_registers(struct pt_regs * regs)
+{
+	/* We either use rdusp() - the USP register, which might not
+	   correspond to the current process for all cases we're called,
+	   or we use the current->thread.usp, which is not up to date for
+	   the current process.  Experience shows we want the USP
+	   register.  */
+	unsigned long usp = rdusp();
+
+	printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n",
+	       regs->irp, regs->srp, regs->dccr, usp, regs->mof );
+	printk(" r0: %08lx  r1: %08lx   r2: %08lx  r3: %08lx\n",
+	       regs->r0, regs->r1, regs->r2, regs->r3);
+	printk(" r4: %08lx  r5: %08lx   r6: %08lx  r7: %08lx\n",
+	       regs->r4, regs->r5, regs->r6, regs->r7);
+	printk(" r8: %08lx  r9: %08lx  r10: %08lx r11: %08lx\n",
+	       regs->r8, regs->r9, regs->r10, regs->r11);
+	printk("r12: %08lx r13: %08lx oR10: %08lx\n",
+	       regs->r12, regs->r13, regs->orig_r10);
+	printk("R_MMU_CAUSE: %08lx\n", (unsigned long)*R_MMU_CAUSE);
+	printk("Process %s (pid: %d, stackpage=%08lx)\n",
+	       current->comm, current->pid, (unsigned long)current);
+
+	/*
+         * When in-kernel, we also print out the stack and code at the
+         * time of the fault..
+         */
+        if (! user_mode(regs)) {
+	  	int i;
+
+                show_stack(NULL, (unsigned long*)usp);
+
+		/* Dump kernel stack if the previous dump wasn't one.  */
+		if (usp != 0)
+			show_stack (NULL, NULL);
+
+                printk("\nCode: ");
+                if(regs->irp < PAGE_OFFSET)
+                        goto bad;
+
+		/* Often enough the value at regs->irp does not point to
+		   the interesting instruction, which is most often the
+		   _previous_ instruction.  So we dump at an offset large
+		   enough that instruction decoding should be in sync at
+		   the interesting point, but small enough to fit on a row
+		   (sort of).  We point out the regs->irp location in a
+		   ksymoops-friendly way by wrapping the byte for that
+		   address in parentheses.  */
+                for(i = -12; i < 12; i++)
+                {
+                        unsigned char c;
+                        if(__get_user(c, &((unsigned char*)regs->irp)[i])) {
+bad:
+                                printk(" Bad IP value.");
+                                break;
+                        }
+
+			if (i == 0)
+			  printk("(%02x) ", c);
+			else
+			  printk("%02x ", c);
+                }
+		printk("\n");
+        }
+}
+
+/* Called from entry.S when the watchdog has bitten
+ * We print out something resembling an oops dump, and if
+ * we have the nice doggy development flag set, we halt here
+ * instead of rebooting.
+ */
+
+extern void reset_watchdog(void);
+extern void stop_watchdog(void);
+
+
+void
+watchdog_bite_hook(struct pt_regs *regs)
+{
+#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
+	local_irq_disable();
+	stop_watchdog();
+	show_registers(regs);
+	while(1) /* nothing */;
+#else
+	show_registers(regs);
+#endif	
+}
+
+/* This is normally the 'Oops' routine */
+void 
+die_if_kernel(const char * str, struct pt_regs * regs, long err)
+{
+	if(user_mode(regs))
+		return;
+
+#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
+	/* This printout might take too long and trigger the 
+	 * watchdog normally. If we're in the nice doggy
+	 * development mode, stop the watchdog during printout.
+	 */
+	stop_watchdog();
+#endif
+
+	printk("%s: %04lx\n", str, err & 0xffff);
+
+	show_registers(regs);
+
+#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
+	reset_watchdog();
+#endif
+	do_exit(SIGSEGV);
+}